Partner API
API Endpoints
Webhooks

Webhooks

Channel ID: webhooks

Get raw stock updates for the store via webhook calls.

Sends a webhook call each time a stock status or price changes, or a new product is added to the retailer’s point of sale.

Channel parameters:

  • string webhookUrl (required): HTTPS endpoint to call with a POST request and a JSON payload on stock changes.
  • string secret (required): Signing secret. Should be an alphanumeric string of between 12 and 64 characters long.
  • boolean enhancedProductData: Set to true to enable product information to be sent alongside inventory information, if available. Depending on your contract, there might be additional charges for including product data. Defaults to false.

Each webhook call has a body that looks like this:

{
    "action": "inventory.update",
    "data": {
        "id": "local:en:GB:000009779712345005",
        "barcode": "9779712345005",
        "status": "in_stock",
        "price": 44.99,
        "currency": "GBP",
        "condition": "new",
        "store": {
            "id": "64491013-b1ea-452c-b93a-85d28c45ebf9",
        },
        "product": { // enhancedProductData only
            "contentLanguage": "en",
            "title": "Men's Classic T-Shirt",
            "brand": "Hanes",
            "description": "Stay comfortable all day long in this classic Hanes t-shirt. Made from soft and durable cotton, this shirt features a ribbed collar and double-needle stitching for long-lasting wear. Available in a variety of colors and sizes.",
            "images": [
                "https://catalog-media.near.st/images/tshirt_front.jpg"
            ],
            "category": "Clothing",
            "attributes": {
                "size": "Medium",
                "color": "Navy Blue"
            },
            "groupId": "123456"
        },
        "createdAt": "2022-01-10T16:03:30Z"
    }
}

Limitations

  • Only a single webhook integration can be set up per store. Setting up a new webhook will override the previously created webhook.
  • Webhooks will be retried up to 3 times if the client responds with a non-2xx status code.

Webhook payload reference

The webhook payload will be a JSON object that consists of two keys:

  • action: indicates the type of event
  • data: contains the details of the inventory item

The following values are available for action:

  • webhook.enabled - webhook has been added (initial ping)
  • inventory.update - inventory item update
  • inventory_source.update - inventory integration status update
  • channel.update - channel integration status update

Webhook enabled: webhook.enabled

Example payload:

{
    "action": "webhook.enabled",
    "data": {
        "retailer": {
            "id": "f35135ff-873a-4c53-9246-40b1267884f5"
        },
        "store": {
            "id": "c23ff0dc-3cdc-4215-a209-7fbf00415ace"
        }
    }
}

Inventory item update: inventory.update

Example payload:

{
    "action": "inventory.update",
    "data": {
        "id": "local:en:GB:000009779712345005",
        "barcode": "9779712345005",
        "status": "in_stock",
        "price": 44.99,
        "currency": "GBP",
        "condition": "new",
        "store": {
            "id": "64491013-b1ea-452c-b93a-85d28c45ebf9",
        },
        "product": { // enhancedProductData only
            "contentLanguage": "en",
            "title": "Men's Classic T-Shirt",
            "brand": "Hanes",
            "description": "Stay comfortable all day long in this classic Hanes t-shirt. Made from soft and durable cotton, this shirt features a ribbed collar and double-needle stitching for long-lasting wear. Available in a variety of colors and sizes.",
            "images": [
                "https://catalog-media.near.st/images/tshirt_front.jpg"
            ],
            "category": "Clothing",
            "attributes": {
                "size": "Medium",
                "color": "Navy Blue"
            },
            "groupId": "123456"
        },
        "createdAt": "2022-01-10T16:03:30Z"
    }
}

Payload keys:

KeyDescription
idString. A normalized ID that represents the unique inventory item.
barcodeString. Plain barcode as represented in the retailer's point-of-sale system. For custom products, this can contain a non-numeric product ID.
status

Enum string. Indicates the stock availaibility of the product:
in_stock
low_stock (quantity less than 3)
out_of_stock

priceNumber. 2 decimal current product price. Includes VAT where applicable.
currencyString. ISO 4217 (opens in a new tab) 3-letter currency code (e.g. GBP, EUR, USD) for the price.
condition

Enum string. Indicates the product condition, which can be:
new
refurbished
used

createdAtString. ISO datetime representing when the inventory item update was created.
store.idRepresents the store ID to which the inventory item belongs.
product.titleOptional string, might be null. Product title, if supplied by the retailer or found in NearSt's global product catalog.
product.contentLanguageOptional string, might be null. Language of the content, represented as a lowercased two-letter ISO 639-1 (opens in a new tab) language code. Currently always returns en. In the future we will enable clients to specify a preferred content language.
product.brandOptional string, might be null. Brand of the product. In the case of media like books, this might contain the author's name.
product.descriptionOptional string, might be null. Long-form description of the product. Might contain basic HTML.
product.imagesOptional array of strings, might be null. One or more images for the product. For most products, only a single image will be present.
product.categoryOptional string, might be null. It specifies the product’s main category.
product.attributesOptional object, might be null. Keys color and size are the only currently supported properties, but this might be extended in the future.
product.groupIdOptional string, might be null It denotes a unique identifier for the group of products.

Inventory source status update: inventory_source.update

Example payload:

{
  "action": "inventory_source.update",
  "data": {
    "store": {
      "id": "1bd8cc75-c78c-48ce-a037-b11255b08031"
    },
    "retailer": {
      "id": "7c3076cc-720a-4c9b-9ece-d2fc97e5db1d"
    },
    "status": "connected", // or disconnected, pending, invalid
    "provider": { // might be null if pending
      "id": "eposnow",
      "label": "EposNow Back-office",
      "type": "point-of-sale",
      "vendor": "EposNow"
    },
    "latestIngest": { // might be null if pending
      "createdAt": "2022-01-10T11:46:03Z",
      "numberOfLines": 2035,
      "validLines": 1867,
      "inStockValidLines": 394
    },
    "warnings": []
}

Channel status update: channel.update

Example payload:

{
  "action": "channel.update",
  "data": {
    "store": {
      "id": "1bd8cc75-c78c-48ce-a037-b11255b08031"
    },
    "retailer": {
      "id": "7c3076cc-720a-4c9b-9ece-d2fc97e5db1d"
    },
    "status": "pending",
    "channel": {
       "id": "google",
       "label": "Google Local Listings",
       "description": "..."
    },
    "warnings": []
}

Example - setting up a webhook

After creating a retailer and creating a store within the retailer account, you can enable the webhook channel by doing a POST request to the /channels endpoint:

POST https://partner-api.near.st/retailers/{retailerId}/stores/{storeId}/channels
Content-Type: application/json
 
{
    "type": "webhook",
    "parameters": {
        "webhookUrl": "https://my-service.com/webhooks/nearst",
        "enhancedProductData": true,
        "secret": "319218c9d1af43cbb0fca550c9809929"
    }
}

This will send a verification webhook call of the type webhook.enabled:

POST https://my-service.com/webhooks/nearst
Content-Type: application/json
X-Webhook-Signature: 2ed7180ae9cae96a0dfc82655686c284faf30d95eaa6e858796199334c56c6d6
 
{
    "action": "webhook.enabled",
    "data": {
        "retailer": { "id": "f35135ff-873a-4c53-9246-40b1267884f5" },
        "store": { "id": "c23ff0dc-3cdc-4215-a209-7fbf00415ace" }
    }
}

Example - validating webhook payload

Every webhook call include a HTTP header X-Webhook-Signature, which contains a HMAC SHA256 digest of the payload signed with the webhook secret defined during the webhook setup.

This allows you to verify the webhook has been sent by NearSt, rather than by a malicious third party trying to change the data you display.

Verifying the signature is relatively simple, here is an example using Javascript:

const crypto = require('crypto');
 
// Store your signing secret somewhere safe!
const secret = process.env.WEBHOOK_SECRET;
 
// Get the signature from the HTTP headers
const signature = request.headers['X-Webhook-Signature'];
 
// Calculate the digest from the HTTP body
const hmac = crypto.createHmac('sha256', secret);
const digest = hmac.update(request.rawBody).digest('hex');
 
// Compare signature to digest
if (signature.length !== digest.length || !crypto.timingSafeEqual(digest, signature)) {
   throw new Error(`Request body digest (${digest}) did not match X-Webhook-Signature: ${signature}`);
}
 
// If we pass - all is good!