For website developers, agencies and e-commerce platforms
Keep stock, prices and availability current automatically.
If a business's stock, prices or availability change often, X-Protocols can read a file on their own website on a schedule and keep an assistant's answers current — no plugin from us to install, no ongoing integration work. This page is the entire contract.
On this page
The short version
Publish a small XML file at any URL on your own site. List one <item> per
product or service whose availability changes. Register that URL once. We read it on the
interval the business chose, and nothing else is required from you afterwards.
Open Connections Live data → Open → New live data stream
Setting up the source
Check what already exists before building anything. Roughly in order of how likely each is to be a 30-second answer rather than new work:
- WooCommerce: check installed plugins for anything with "Feed", "Google Shopping" or "Merchant Center" in the name (e.g. "Product Feed PRO", "Google Listings & Ads"). Its settings page shows a feed URL directly.
- Shopify: check Sales Channels for "Google & YouTube" — if installed, a feed already exists.
- PrestaShop / Magento / other: search the admin for "product feed" or "Google Shopping export" — nearly every mainstream platform has an official or community module for this already.
- Already found one for Google Shopping/Merchant Center? You're most of the way there — the format below is deliberately close to it. You likely only need to add or rename a handful of fields, not build one from scratch.
- Nothing above applies? Building one from scratch is genuinely simple — see the format below. It is a static file your server (or even a scheduled script) can regenerate periodically; no framework, database driver or library is required on your end, just valid XML in this shape.
Once the file exists at a stable URL, register it: Open Connections, then Live data → Open → New live data stream. The business owner can do this themselves, or an agency can do it on their behalf. There is nothing else to configure — no key, no secret, no code.
The format
One <feed> element, one <item> per thing whose
availability changes. Everything except id is optional:
<?xml version="1.0" encoding="UTF-8"?>
<feed>
<item>
<id>SKU-123</id>
<availability>in_stock</availability>
<price currency="EUR">49.90</price>
<quantity>4</quantity>
<location_id>store-1</location_id>
<updated_at>2026-08-05T12:00:00Z</updated_at>
</item>
<item>
<id>SKU-124</id>
<availability>out_of_stock</availability>
</item>
</feed>
Mapping, field by field
id is the join. It must match the reference code (external ID)
of that same item in the business's records. An id that matches nothing is not an
error and is not a warning you will see in your own logs — the update simply has nothing to
attach to. If one thing on this page is worth checking twice, it is this.
| Field | Required? | What it means |
|---|---|---|
id | Required | Your own product/service code. Must match the reference code (external ID) used for that same item in the business's records. |
availability | Optional | in_stock or out_of_stock. Use this if you don't track an exact number. |
quantity | Optional | An exact count, if you have one. Overrides availability when both are given. |
price | Optional | A number, with a currency attribute (e.g. currency="EUR"). |
location_id | Optional | Only needed if the business has more than one location/warehouse and stock differs between them. |
updated_at | Optional | ISO 8601 timestamp (e.g. 2026-08-05T12:00:00Z). If you leave it out, we use the time we read the file. |
Refresh
The business picks the interval when the stream is created: every 5, 15 or 30 minutes,
hourly, every 6 hours, or once a day. This is a scheduled read, not a real-time push. If a
business needs stock to change within seconds, that is the push route — POST /ingest/{stream}
in the API documentation — which does need a developer.
Each read sends the validators from the previous successful one, so an unchanged file costs your
server a 304 and no transfer at all. Honouring ETag or
Last-Modified on your side is worth doing and is not required.
GET /your-feed.xml HTTP/1.1 User-Agent: X-Protocols-LiveDataFeed/1.0 (+https://x-protocols.com/docs/live-data-feed) Accept: application/xml,text/xml If-None-Match: "<etag from our last successful read>" If-Modified-Since: <date from our last successful read>
That User-Agent is the one to allow-list if the site is behind a WAF or a bot filter. A feed that answers a browser and blocks us is the commonest reason a correctly formatted file never updates anything.
Access and authentication
| The feed URL | Must be reachable over plain http:// or
https:// with no credentials at all. We send a User-Agent, an Accept and
the conditional headers — no Authorization, no basic auth, no cookie. A feed
behind any login is unreachable, and always will be. |
| Keeping it private | Put an unguessable random path in the URL
(/feed/8f3c1a…xml) rather than a password. It is not indexed, it is not linked
from anywhere, and it can be rotated by changing the path and re-registering. |
| Bearer tokens | Belong to the query API — the keys a publisher creates in Developer access, which identify whoever is reading their published records. They are never presented to your server, and they have nothing to do with this feed. |
| Authenticated ingestion | Exists, and it is the other direction:
POST /ingest/{stream}, signed HMAC-SHA256 with a shared secret. Use that when you
want to push the moment something changes instead of publishing a file we read. |
When something goes wrong
Every read records its outcome, and the business can see it on the stream's own page — including the failures, with the reason. What each failure does:
| The URL cannot be reached | Recorded as a failed read. The previously loaded data stays as it was; nothing is deleted because a file went missing. |
| Any status other than 200 or 304 | Same: recorded with the status code, previous data kept. |
| The XML does not parse | Recorded as invalid XML. Nothing in the file
is applied — a half-parsed feed is worse than a stale one. |
| More than 50000 items, or over 16MB | Refused whole. Split the feed or narrow it to the items whose availability actually changes. |
An item with no id | Skipped, not fatal. One bad row never blocks the rest of the file. |
An id matching no record | Accepted and applied to nothing. This is the silent one; see the note on mapping above. |
A stream that keeps failing is shown as failing on Connections rather than quietly retrying forever.