Skip to content

Cartenvo Integration Hub docs

Integration Hub Pro

Integration Hub Pro for nopCommerce: webhook filters and Liquid payload templates, signed inbound webhooks from an ERP, alerts by email, Slack and Teams, and a year of delivery history.

On this page

Integration Hub Pro is a paid add-on to the free Integration Hub plugin for nopCommerce 4.80, 4.90 and 5.00. It adds:

  • Filters and payloads: send each webhook only the events it needs, in the receiver's own format.
  • Inbound webhooks: let an ERP, warehouse or accounting system push stock, prices, order statuses and shipments into the store.
  • Alerts by email, Slack and Microsoft Teams.
  • History: keep the delivery log up to a year, search inside messages, and export it as CSV.

Everything is under Configuration → Integration Hub → Pro. Pro needs the free plugin's release 4 or later.

Filters and payloads

Open Pro → Filters and payloads and choose a webhook, or use the "Filter and payload (Pro)" link on a webhook's own page.

Which events go out

An event goes to the webhook only when every condition matches. You can test these fields:

FieldValuesApplies to
StoreStore IDsEvery event raised in a store
Order totalA number, in the primary currency (is at least, is at most)Orders and shipments
Payment methodSystem names, such as Payments.CheckMoneyOrderOrders and shipments
Shipping methodNames, as on the orderOrders and shipments
Billing country, Shipping countryTwo-letter ISO codesOrders, shipments, customers
Customer roleSystem names, such as RegisteredOrders, shipments, customers
Product category, Manufacturer, VendorIDsOrders and shipments (any item), products, stock, reviews

A condition about something an event doesn't have, such as a payment method on a product, doesn't apply to that event. Shipments use their order's details. The rule page lists the values the store has.

Payload templates

Without a template the webhook gets the standard message (see the webhook reference). A Liquid template replaces the whole body. It can use the standard message's fields (id, type, occurredOnUtc, store, data, context) and target (id, name). The template must write a JSON object:

liquid
{
  "orderNumber": {{ data.number | json }},
  "status": {{ data.status | lookup: "status" | json }},
  "total": {{ data.totals.total }},
  "lines": [
  {% for item in data.items %}
    { "sku": {{ item.sku | json }}, "qty": {{ item.quantity }} },
  {% endfor %}
  ]
}
  • Put | json after text values, so quotes, accents and missing values (null) are written correctly.
  • Trailing commas and comments are allowed, which keeps loops simple.
  • Lookup tables translate values into the receiver's codes. Write a table name in brackets, then value = replacement lines, and use the table as {{ data.status | lookup: "status" }}. A value that isn't in the table stays as it is.
Example
[status]
Pending = NEW
Processing = OPEN
Complete = DONE

Preview builds the message for a real order, product or customer with the settings on the form, saved or not. It also says whether the event would pass the conditions.

If a template fails for a message, for example because it writes invalid JSON, the message is not sent in the standard shape. It counts as a failed attempt, is retried on the normal schedule, and the delivery log shows why. Fix the template and the waiting messages go out in order. "Send test" always sends the standard test message.

Templates run in a sandbox. They can't read files or other templates, or reach .NET objects. Loops are limited to 10,000 steps, each render to 2 seconds, and the output to 2 MB.

Inbound webhooks

Add an endpoint under Pro → Inbound for each system that sends changes. Each endpoint has:

  • its own address, https://{store}/api/cartenvo/v1/inbound/ihin_…;
  • its own secret;
  • the message types it accepts;
  • optionally, one store whose orders it may change.

Sending a message

Post JSON to the endpoint's address:

JSON
{ "id": "ERP-1001", "type": "stock.set", "data": { "lines": [ { "sku": "SHIRT-BLUE-L", "quantity": 12 } ] } }
  • id is the ERP's own ID for the change, up to 200 characters. A message with an ID that was already applied is not applied again. The store answers with the first answer and the header X-Cartenvo-Duplicate: true. A message that was rejected can be sent again with the same ID once it's fixed.
  • type is one of the types below, or ping to check the connection, the signature and the template.
  • data has the same shape as the matching sync API call.
  • Dry run: add ?dryRun=true to the address, or "dryRun": true to the body. The store checks everything and reports what would change, and changes nothing.
TypedataSync API equivalent
stock.setlines of sku (or productId, combinationId, warehouseId) with quantity or adjustment; optional reasonPOST stock
price.setlines of sku with price, oldPrice, productCostPOST prices
order.statusthe order, plus orderStatus, paymentStatus, notifyCustomerPOST orders/{id}/status
shipment.addthe order, plus items, trackingNumber, ship, deliver, notifyCustomerPOST orders/{id}/shipments

Name the order in one of three ways:

  • "orderId": 12;
  • "orderNumber": "1012";
  • "externalReference": {"system": "odoo", "reference": "SO001"}, the order's number in the ERP, saved through the sync API or an ERP connector.

If the endpoint has an ERP name set, "externalReference": "SO001" alone is enough.

Signing

Sign each call the same way the Hub signs its own webhooks:

  • X-Cartenvo-Timestamp is the current Unix time.
  • X-Cartenvo-Signature is sha256= followed by the hex HMAC-SHA256 of "{timestamp}.{body}", using the endpoint's secret.

The store accepts a timestamp up to 5 minutes from its own clock. For systems that can't sign, switch on "Also accept the secret as a bearer token". They then send Authorization: Bearer {secret} instead. Calls must use https.

Reading the ERP's own format

When the ERP can't send the Hub's format, give the endpoint a Liquid template. The template reads body (the JSON received), headers and endpoint, and writes an inbound message:

liquid
{
  "id": {{ body.docNo | json }},
  "type": "stock.set",
  "data": { "lines": [
    {% for i in body.items %}{ "sku": {{ i.code | json }}, "quantity": {{ i.onHand }} },{% endfor %}
  ] }
}

Answers

StatusMeaning
200Applied, or a dry run. The body has status (applied, dryRun or ok) and the result, which has the same shape as the sync API's answer.
400The JSON, the message or data isn't valid. detail says what's wrong.
401Missing or wrong signature or token, or a timestamp that's too old.
403The endpoint doesn't accept this type, or Pro has no active licence.
404There's no endpoint at this address, it's switched off, or the order wasn't found.
409The same ID is still being applied, or the order can't change that way.
422The endpoint's template couldn't read the message.
503The store is busy (Retry-After is set). Send the same message again.

Errors use the sync API's problem format: type, title, status, detail and code. Every call is logged under Pro → Inbound → Inbound log, with the body received and the answer sent.

Alerts

Under Pro → Alerts, choose where alerts go: email addresses, a Slack incoming webhook, a Teams workflow ("Post to a channel when a webhook request is received"), or any mix. Then choose when they're sent:

  • A webhook has failed a number of attempts in a row (5 by default). This happens before its messages run out of retries. You get at most one alert per webhook every 6 hours, and a note when it works again.
  • An API key is used from an address it hasn't used before. This is checked every 5 minutes.
  • Inbound calls keep being refused: 10 calls with a wrong signature or token within an hour.
  • Stock hasn't synced through the sync API or an inbound webhook for a number of hours.

"Send a test alert" sends to every channel and reports any channel that failed.

History

The free plugin keeps the delivery log for up to 90 days. With Pro, the limit under Settings goes up to 365 days. Pro → History searches the log by text in the message, the answer or the error, by event ID (evt_…), webhook, status, event, entity and dates. Export CSV downloads up to 100,000 rows, with or without the bodies. Inbound calls are kept for the same number of days.

Licence

Paste the licence text (CIHP1.…) under Pro → Licence. The licence is checked inside the store, against each store's domain, and Pro never calls home. On a development address (localhost, *.test, *.local) Pro works without a licence.

Without an active licence, Pro changes nothing:

  • webhooks get every event in the standard shape;
  • inbound endpoints answer 403;
  • alerts stop;
  • the log limit goes back to 90 days.

Your settings are kept. A licence keeps working for 14 days after its expiry date.

Integration Hub Pro is a paid add-on, free on development addresses.

Pricing and early access