Vendor documentation
Integrate stock alerts and on-demand stock checks.
This guide is designed to be handed directly to your developer or pasted into an AI coding agent. Vendor alerts push stock events to users. On-demand vendors let users manually check your stock from inside the app.
Fastest setup
Copy-paste this into your favourite coding agent
Copy-paste this prompt into your favourite coding agent. It includes the endpoints, authentication, data structures, examples, validation rules, and tests it needs to build the integration properly.
You are integrating a vendor inventory system with The Crimson Market Stock Checker.
Build the integration end-to-end in this codebase. Use environment variables for every secret and add tests for payload validation, auth failures, success responses, and no-stock results.
Environment variables to add:
- STOCKCHECKER_VENDOR_SOURCE_ID: source id from the Stock Checker vendor dashboard.
- STOCKCHECKER_VENDOR_CLIENT_ID: client id from the Crimson Market developer application.
- STOCKCHECKER_VENDOR_CLIENT_SECRET: client secret from the Crimson Market developer application.
- STOCKCHECKER_ON_DEMAND_API_KEY: API key that Stock Checker will send to this vendor endpoint.
Integration surface 1: Vendor alert sender
- Purpose: push important stock events into Stock Checker so subscribed users receive push notifications and inbox cards.
- Endpoint:
POST https://www.thecrimsonmarket.com/stockchecker/api/vendor/events/<STOCKCHECKER_VENDOR_SOURCE_ID>
- Auth: send either Basic auth using clientId:clientSecret, or these headers:
x-client-id: <STOCKCHECKER_VENDOR_CLIENT_ID>
x-client-secret: <STOCKCHECKER_VENDOR_CLIENT_SECRET>
- Also send x-request-id for idempotency/dedupe. Use a deterministic id based on product id/url + event type + price/status + stock state. Do not include timestamps in the dedupe id.
- Content-Type: application/json.
Vendor alert request JSON schema:
{
"title": "string, required, product or event title shown to users",
"eventType": "string, recommended, examples: Restock, New Product, Price Drop, Raffle, Release",
"price": "string, recommended, include currency, example: 189.95 AUD",
"status": "string, recommended, examples: In stock, Low stock, Online only, Sold out",
"productUrl": "string, strongly recommended HTTPS URL users can open",
"sourceUrl": "string, optional vendor homepage or category URL",
"imageUrl": "string, strongly recommended HTTPS product image URL",
"iconUrl": "string, optional vendor/store icon URL",
"body": "string, optional short notification body. If omitted, Stock Checker builds one from eventType/status/price.",
"releaseTime": "string, optional release time if relevant",
"note": "string, optional important context",
"states": "string, optional state/province availability, e.g. VIC or CA",
"color": "string, optional hex color",
"timestamp": "number|string, optional source timestamp",
"links": [
{
"label": "string, required if url is present",
"url": "string, required HTTPS URL"
}
],
"fields": [
{
"title": "string",
"value": "string",
"short": true,
"links": [
{
"label": "string",
"url": "string"
}
]
}
]
}
Useful alert payload example:
{
"title": "Pokemon TCG Example Booster Box",
"eventType": "Restock",
"price": "189.95 AUD",
"status": "In stock",
"productUrl": "https://your-store.example/products/example-booster-box",
"sourceUrl": "https://your-store.example",
"imageUrl": "https://your-store.example/images/example-booster-box.jpg",
"body": "Pokemon restock from Your Store",
"links": [
{
"label": "Buy",
"url": "https://your-store.example/products/example-booster-box"
}
],
"fields": [
{
"title": "Stock",
"value": "24",
"short": true
},
{
"title": "SKU",
"value": "example-booster-box",
"short": true
}
]
}
Expected alert response:
- 202 JSON: { "ok": true, "received": true, "eventId": "...", "queue": {...} }
- 400 JSON when title is missing.
- 401 JSON when source id/client credentials are invalid.
Alert sending rules:
- Send only useful alerts. Do not send blank checkout-success, test, heartbeat, or low-information messages.
- Treat title, productUrl, imageUrl, eventType, status, and price as required for a high-quality user card, even if the API only hard-requires title.
- Deduplicate before sending. The same product/event/status/price/stock state should not spam users.
- Rate limit retries with exponential backoff. Retry 5xx/network errors; do not retry 400/401.
- Never expose client secrets in logs.
Integration surface 2: On-demand stock endpoint hosted by this vendor
- Purpose: Stock Checker users can manually check this vendor's stock from inside the app.
- Build an HTTPS POST endpoint, for example:
POST /stockchecker/on-demand
- Require an API key header. Default header should be:
x-api-key: <STOCKCHECKER_ON_DEMAND_API_KEY>
- Content-Type: application/json.
- Respond within 12 seconds.
Stock Checker on-demand request JSON schema:
{
"requestType": "stockchecker.onDemand.v1",
"vendor": {
"id": "string, source id configured in Stock Checker",
"companyName": "string",
"title": "string shown to users",
"category": "string, examples: Pokemon, Sneakers, Watches, Computing",
"region": "string, examples: AU, US, UK, EU, Global"
},
"configuration": {
"postcode": "string, optional user postcode",
"filteringState": "string, optional state/region filter",
"limitingResults": 5
},
"items": [
{
"sku": "string, required product SKU",
"itemName": "string, required product name",
"productId": "string, optional product id"
}
]
}
On-demand response JSON schema:
{
"results": [
{
"sku": "string, must match the requested item sku when possible",
"itemName": "string, product display name",
"locations": [
{
"storeName": "string, required, e.g. Online or Melbourne CBD",
"stockLevel": 24,
"phoneNumber": "string, optional",
"address": "string, optional physical address or product URL",
"coordinates": {
"lat": -37.8136,
"lng": 144.9631
}
}
]
}
]
}
On-demand response aliases accepted by Stock Checker:
- The top-level array can be named results or stock.
- Result sku can also be productId or id.
- Result itemName can also be title or name.
- Location stockLevel can also be quantity or stock.
- Location phoneNumber can also be phone.
- Location coordinates can be { lat, lng } or top-level lat/lng on the location.
On-demand no-stock rule:
- If a requested item is found but unavailable, return that item with locations: [].
- Do not omit the item unless the sku is invalid or unknown.
On-demand example request:
{
"requestType": "stockchecker.onDemand.v1",
"vendor": {
"id": "ondemand-example",
"companyName": "Your Store",
"title": "Your Store Pokemon AU",
"category": "Pokemon",
"region": "AU"
},
"configuration": {
"postcode": "3000",
"filteringState": "VIC",
"limitingResults": 5
},
"items": [
{
"sku": "example-booster-box",
"itemName": "Pokemon TCG Example Booster Box",
"productId": "example-booster-box"
}
]
}
On-demand example response:
{
"results": [
{
"sku": "example-booster-box",
"itemName": "Pokemon TCG Example Booster Box",
"locations": [
{
"storeName": "Online",
"stockLevel": 24,
"address": "https://your-store.example/products/example-booster-box"
},
{
"storeName": "Melbourne CBD",
"stockLevel": 6,
"phoneNumber": "+61 3 9000 0000",
"address": "123 Example St, Melbourne VIC",
"coordinates": {
"lat": -37.8136,
"lng": 144.9631
}
}
]
}
]
}
On-demand HTTP status rules:
- 200: valid check, including no-stock results.
- 400: invalid requestType or invalid items array.
- 401: missing/invalid API key.
- 429: rate limited.
- 500/502/503: temporary vendor-side failure.
Minimal Node/Express on-demand endpoint to implement if this project uses Express:
import express from "express";
const app = express();
app.use(express.json());
const API_KEY = process.env.STOCKCHECKER_ON_DEMAND_API_KEY;
app.post("/stockchecker/on-demand", async (req, res) => {
if (req.header("x-api-key") !== API_KEY) {
return res.status(401).json({ error: "Unauthorized" });
}
if (req.body?.requestType !== "stockchecker.onDemand.v1" || !Array.isArray(req.body.items)) {
return res.status(400).json({ error: "Invalid Stock Checker on-demand payload" });
}
const results = await Promise.all(req.body.items.map(async (item) => {
// Replace this with the real inventory lookup for item.sku/productId/itemName.
const stockLevel = 0;
return {
sku: item.sku,
itemName: item.itemName,
locations: stockLevel > 0
? [{ storeName: "Online", stockLevel, address: "https://your-store.example" }]
: []
};
}));
return res.json({ results });
});
Implementation checklist:
- Add alert sender function with deterministic x-request-id.
- Add on-demand endpoint with API-key auth.
- Validate all inbound/outbound payloads.
- Add tests for auth failure, invalid payload, in-stock, no-stock, and vendor API errors.
- Add safe logging that includes request ids but never secrets.
- Document the env vars and how to run a local test.Recommended Flow
- Create an application at `developer-community` and copy your client credentials.
- Open the vendor dashboard and create one source per company, category, and region.
- Use alerts for fast restocks, launches, price drops, raffles, and important updates.
- Use on-demand when users should be able to manually check your stock.
- Ask for approval after testing with a real in-stock item and a no-stock item.
Categories And Regions
Choose the most specific category and region available. Good examples are `Pokemon`, `One Piece`, `MTG`, `Sneakers`, `Watches`, `Computing`, `Electronics`, `Tickets`, `Collectibles`, `Deals`, and `General`.
Use regions like `US`, `CA`, `AU`, `NZ`, `UK`, `EU`, `JP`, `KR`, `SG`, `MY`, `TH`, `PH`, `MX`, or `Global`. Use `Global` only when the same event is genuinely useful worldwide.
Vendor Alerts
Send alerts to `POST https://www.thecrimsonmarket.com/stockchecker/api/vendor/events/:sourceId`. Authenticate with Basic auth using `clientId:clientSecret`, or with `x-client-id` and `x-client-secret` headers.
{
"title": "Pokemon TCG Example Booster Box",
"eventType": "Restock",
"price": "189.95 AUD",
"status": "In stock",
"productUrl": "https://your-store.example/products/example-booster-box",
"imageUrl": "https://your-store.example/images/example-booster-box.jpg",
"body": "Pokemon restock from Your Store",
"links": [
{
"label": "Buy",
"url": "https://your-store.example/products/example-booster-box"
}
],
"fields": [
{
"title": "Stock",
"value": "24",
"short": true
}
]
}Required fields are `title` and `productUrl`. Strongly recommended fields are `eventType`, `price`, `status`, `imageUrl`, `body`, `links`, and `fields`.
On-demand Vendors
Your on-demand endpoint must be HTTPS, accept `POST` JSON, require an API key header, and respond within 12 seconds. Stock Checker sends this request:
{
"requestType": "stockchecker.onDemand.v1",
"vendor": {
"id": "ondemand-example",
"companyName": "Your Store",
"title": "Your Store Pokemon AU",
"category": "Pokemon",
"region": "AU"
},
"configuration": {
"postcode": "3000",
"filteringState": "VIC",
"limitingResults": 5
},
"items": [
{
"sku": "example-booster-box",
"itemName": "Pokemon TCG Example Booster Box",
"productId": "example-booster-box"
}
]
}Your endpoint should return this structure:
{
"results": [
{
"sku": "example-booster-box",
"itemName": "Pokemon TCG Example Booster Box",
"locations": [
{
"storeName": "Online",
"stockLevel": 24,
"address": "https://your-store.example/products/example-booster-box"
},
{
"storeName": "Melbourne CBD",
"stockLevel": 6,
"phoneNumber": "+61 3 9000 0000",
"address": "123 Example St, Melbourne VIC",
"coordinates": {
"lat": -37.8136,
"lng": 144.9631
}
}
]
}
]
}Empty `locations` means the check succeeded but no stock was found. `results` is preferred, though `stock` is also accepted.
Minimal Express Endpoint
import express from "express";
const app = express();
app.use(express.json());
const API_KEY = process.env.STOCKCHECKER_VENDOR_API_KEY;
app.post("/stockchecker/on-demand", (req, res) => {
if (req.header("x-api-key") !== API_KEY) {
return res.status(401).json({ error: "Unauthorized" });
}
if (req.body?.requestType !== "stockchecker.onDemand.v1") {
return res.status(400).json({ error: "Invalid requestType" });
}
const results = (req.body.items || []).map((item) => ({
sku: item.sku,
itemName: item.itemName,
locations: [
{
storeName: "Online",
stockLevel: 10,
address: `https://your-store.example/search?q=${encodeURIComponent(item.itemName)}`
}
]
}));
return res.json({ results });
});
app.listen(3000);Approval Checklist
- Alert events include useful title, URL, image, price, status, and event type.
- On-demand endpoint is HTTPS and protected by an API key.
- On-demand endpoint returns `results[]` with `sku`, `itemName`, and `locations[]`.
- No-stock checks return an empty `locations` array.
- Categories and regions are specific enough for users to subscribe comfortably.
- No blank checkout-success or low-information alerts are sent.