Skip to main content

Receive Ship Confirmations

Playbook can process ship confirmations from one ore many warehouses via a webhook endpoint.

When the Webhook - Process Shipments Playbook Step is installed on a business it provides a synchronous endpoint that can be used to post order fulfillment acknowledgements (ship confirmations) back to ChannelApe. It handles much more than our order update endpoint. It will match up to pending fulfillments and update fulfillment status. It will also handle making inventory adjustments on the warehouse and virtual sales channel locations when needed for complete, short, and backorder shipments.

Configuration

Install the Webhook - Process Shipments Playbook Step on a business using the app.

  1. Login to app.channelape.io

  2. Install playbook step on business by going to this URL: https://app.channelape.io/{{businessId}}/playbook/steps/a970417b-bb48-47cc-b3ea-58ca5d9edbc1/install

    1. Replace businessId with the ID of the business you are using
  3. Ensure Synchronous is enabled

  4. Ensure Authenticated Callback is enabled

    1. This flag will use the session ID passed in from X-Channel-Ape-Authorization-Token header on the callbacks endpoint
  5. Set version to STAGING if this is a Staging Business otherwise use PRODUCTION

  6. Under Order Filtering you may optionally select 1 or many channels if you know that you will only be processing ship confirmations for those channels. All other fields can be left alone since they are not used.

  7. Enter a valid value for your Virtual Sales Channel Location ID where inventory adjustments could be made based on ship confirmation activity.

  8. Fill in the Warehouse Location Map with all of the locations you expect to receive ship confirmations for.

  9. Select Install

  10. Refresh the Playbook ➝ Steps Configuration page and select the new step you just installed

  11. Select Copy Callback URL

    1. This URL is your endpoint to post ship confirmations too
    2. You will need to pass in a valid X-Channel-Ape-Authorization-Token header for the business along with the payload
  12. Optionally select 1 or many channels on the Steps Configuration page

    1. Will help with additional filtering when receiving a payload. This is usually only needed if you wish to match a Purchase Order Number or Warehouse Order ID that is duplicated across channels. In this case you would select the single channel you are interested in receiving ship confirmations for.

Example

Given the following values:

[
{
"warehouse": "RJT1",
"company": "United Parcel Service",
"locationId": "942",
"name": "UPS East Coast",
"id": "UPSF",
"zipCode": "40165"
},
{
"warehouse": "RJT2",
"company": "United Parcel Service",
"locationId": "874",
"name": "UPS West Coast",
"id": "UPSW",
"zipCode": "91752"
}
]
  • Order with purchaseOrderNumber of CAT333 has 1 PENDING fulfillment with the following line items:
    • SKU sku-1, Quantity 2
    • SKU sku-2, Quantity 3

Request sent: POST https://callbacks.channelape.com/v1/suppliers/f81c87c7-2692-4088-a396-05872695ff93/callbacks

Headers sent:

X-Channel-Ape-Authorization-Token: e375b408-3c06-41ee-9df2-00402c7472b1
Content-Type: application/json

Payload sent:

{
"orderUpdate": {
"fulfillments": [
{
"purchaseOrderNumber": "CAT333", // optional
"additionalFields": [
{
"name": "warehouse_order_id",
"value": "CAT333-3"
}
],
"locationId": "874",
"shippingCompany": "UPS",
"shippingMethod": "UPS GROUND",
"trackingNumber": "54545412165451",
"status": "OPEN",
"lineItems": [
{
"sku": "sku_1",
"quantity": 2
},
{
"sku": "sku_2",
"quantity": 3
}
]
}
]
}
}

Will return a 200 Response Status

And a Response Body of:

{
"updateResult": {
"inventoryAdjustmentCount": 2,
"inventorySetCount": 0,
"orderActivityCount": 0,
"orderUpdateCount": 1
}
}

And Order with purchaseOrderNumber of CAT333 has 1 OPEN fulfillment with the following line items: SKU sku-1, Quantity 2 SKU sku-2, Quantity 3

And the following inventory adjustments are made:

  • SKU sku-1, Location ID 874
    • AVAILABLE_TO_SELL Quantity -2
    • COMMITTED Quantity -2
  • SKU sku-2, Location ID 874
    • AVAILABLE_TO_SELL Quantity -3
    • COMMITTED Quantity -3

Workflow

Set X-Channel-Ape-Authorization-Token header to the API Account Secret Key (see here for more information).

Setup a flow in integration to map ship confirmations to the expected JSON format. Send the JSON in the request body of a POST call to the URL you received in setup. The request body should look something like:

{
"orderUpdate": {
// id, channelOrderId, purchaseOrderNumber, or warehouse_order_id are required to match
"id": "order_id",
"channelOrderId": "channel_order_id",
"purchaseOrderNumber": "purchase_order_number",
"fulfillments": [
{
"id": "fulfillment_id", // optional
"additionalFields": [
{
"name": "warehouse_order_id", // optional as long as id, channelOrderId, or purchaseOrderNumber are included
"value": "warehouse_1"
},
{
"name": "some_extra_data", // optional
"value": "some_extra_data_value"
},
{
"name": "more_extra_data", // optional
"value": "more_extra_data"
}
],
"supplierId": "supplierIdValue", // optional
"shippingCompany": "UPS", // optional
"shippingMethod": "UPS GROUND", // optional
"trackingNumber": "54545412165451",
"trackingUrls": [
// optional
"https://example.tracking/445687484",
"https://other.tracking/4456874895355"
],
"shippedAt": "2022-08-10T19:46:05.014Z", // optional - defaults to current time
"locationId": "location_1", // maps to locationId within WAREHOUSE_LOCATION_MAP
"status": "OPEN", //Can be OPEN|SUCCESS|CANCELED|PENDING|NEW|BACKORDER by is typically OPEN for ship confirmations coming back from the warehouse
"lineItems": [
{
//Supply either id or sku both are acceptable but generally stick with sku
"id": "linItem_id",
"sku": "sku_1",
"title": "sku_1 title", // optional
"additionalFields": [
// optional
{
"name": "some_extra_data",
"value": "some_extra_data_value"
}
],
"grams": 450, // optional
"price": 1500, // optional
"shippingPrice": 500, // optional
"shippingTax": 25, // optional
"quantity": 9,
"shippingMethod": "UPS GROUND", // optional
"vendor": "channel ape" // optional
}
]
}
]
}
}

The order id , channelOrderId , purchaseOrderNumber, or warehouse_order_id (found within fulfillment[x].additionalFields) are required to identify the order.

For fulfillments.lineItems an identifier to id or sku has to be defined and the quantity.

locationId should be mapped to a value within the WAREHOUSE_LOCATION_MAP. It will not attempt to change a fulfillment that's locationId is not in the current context.

Anything else on fulfillments and its descendants can be defined and it'll be merged in. Note that anything else on the parent order object won't be merged in and ignored. Don't attempt to do an order state transition or update the order lineItems.

If no result comes back a 204 Response Status is returned with an empty Response Body. If something is wrong with the input a 400 Response Status is returned with an error trying to explain what was wrong. If everything worked it will return a 200 Response Status with the following Response Body:

{
"updateResult": {
"inventoryAdjustmentCount": 1,
"inventorySetCount": 2,
"orderActivityCount": 3,
"orderUpdateCount": 4
}
}

The numbers will reflect the amount of results updated.

Partial Fulfillments

Orders are typically processed with a single ship confirmation message. If items are under-fulfilled or absent from this message, we assume they are backordered. However, certain integrations necessitate ChannelApe to receive multiple ship confirmation messages for a single order fulfillment. If this applies, enable the "partial fulfillments" feature to indicate that multiple messages per order fulfillment are permissible.

warning

If you enable partial fulfillments there are less protections for exceptional shipping cases like short shipments.

Config

To enable partial fulfillments just add the following to the body of the request:

{
"fulfillmentOptions": {
"partialShipments": true
},
...[rest of the request]
}

Example Workflow

Given the example order:

{
"id": "orderId_1",
"status": "IN_PROGRESS",
"purchaseOrderNumber": "purchase_1",
"fulfillments": [
{
"additionalFields": [
{
"name": "warehouse_order_id",
"value": "warehouse_1"
}
],
"trackingNumber": "3903289892389238932",
"locationId": "locationId_1",
"shippingCompany": "UPS",
"shippingMethod": "Ground",
"status": "PENDING",
"lineItems": [
{
"sku": "sku_1",
"quantity": 2
},
{
"sku": "sku_2",
"quantity": 3
}
]
}
]
}

Sending the following partial fulfillment:

{
"fulfillmentOptions": {
"partialShipments": true
},
"orderUpdate": {
"purchaseOrderNumber": "purchase_1",
"fulfillments": [
{
"additionalFields": [
{
"name": "warehouse_order_id",
"value": "warehouse_1"
}
],
"status": "OPEN",
"locationId": "locationId_1",
"lineItems": [
{
"quantity": 2,
"sku": "sku_1"
}
]
}
]
}
}

Will return the following result:

{
"updateResult": {
"inventoryAdjustmentCount": 2,
"inventorySetCount": 0,
"orderActivityCount": 0,
"orderUpdateCount": 1
}
}

The state of the order after this shipment has happened will be as follows:

{
"id": "orderId_1",
"status": "IN_PROGRESS",
"purchaseOrderNumber": "purchase_1",
"fulfillments": [
{
"additionalFields": [
{
"name": "warehouse_order_id",
"value": "warehouse_1"
}
],
"trackingNumber": "3903289892389238932",
"locationId": "locationId_1",
"shippingCompany": "UPS",
"shippingMethod": "Ground",
"status": "OPEN",
"lineItems": [
{
"sku": "sku_1",
"quantity": 2
}
]
},
{
"additionalFields": [
{
"name": "warehouse_order_id",
"value": "warehouse_1"
}
],
"trackingNumber": "3903289892389238932",
"locationId": "locationId_1",
"shippingCompany": "UPS",
"shippingMethod": "Ground",
"status": "PENDING",
"lineItems": [
{
"sku": "sku_2",
"quantity": 3
}
]
}
]
}

A second process shipment call can then be made to fulfill the remaining fulfillment.