SStock Hunter

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

  1. Create an application at `developer-community` and copy your client credentials.
  2. Open the vendor dashboard and create one source per company, category, and region.
  3. Use alerts for fast restocks, launches, price drops, raffles, and important updates.
  4. Use on-demand when users should be able to manually check your stock.
  5. 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.