API-HUB ships eight workflow JSON files in theDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/VisualGraphxLLC/API-HUB/llms.txt
Use this file to discover all available pages before exploring further.
n8n-workflows/ directory. Each file is a self-contained n8n workflow that can be imported directly into the n8n editor. None of them activate automatically — you import, bind credentials, then manually activate.
Workflow index
| File | Trigger | Purpose |
|---|---|---|
vg-ops-pull.json | Manual / Daily | Pull OPS categories and products → hub /api/ingest/{sid}/* |
catalog-sync-weekly.json | Sunday 1 AM | Full sellable catalog sync per supplier |
pricing-sync-daily.json | Daily | Delta pricing sync for all active suppliers |
inventory-sync-hourly.json | Hourly | Delta inventory sync |
closeouts-monthly.json | 1st of month | Closeouts mode sync |
ops-push.json | Webhook | Apply markup and push hub products → OPS storefront |
ops-master-options-pull.json | Daily | Pull OPS master options → hub /api/ingest/master-options |
sanmar-sftp-pull.json | Daily | SanMar SFTP pull → hub /api/ingest/{sid}/* |
Environment variables used in all workflows
Workflows reference environment variables using n8n’s{{ $env.VARIABLE }} expression syntax. Set these in your repo-root .env — Docker Compose forwards them to the n8n container automatically.
| Variable | Value in Docker Compose | Description |
|---|---|---|
API_BASE_URL | http://api:8000 | FastAPI service address. In production, set to your public or internal API hostname. |
INGEST_SHARED_SECRET | your secret | Sent as the X-Ingest-Secret header on every POST to /api/ingest/* and /api/push-log. Must match the value in the FastAPI container. |
Workflow details
vg-ops-pull.json — Pull OPS catalog (Manual / Daily)
vg-ops-pull.json — Pull OPS catalog (Manual / Daily)
Look up VG supplier
GET {{ $env.API_BASE_URL }}/api/suppliers and filters for the supplier with slug = 'vg-ops'. Fails fast with a descriptive error if the row is missing or is_active = false.Pull categories
getManyProductCategory operation with pagination to fetch the full product_category GraphQL response.Pull products
getManyProductDetailed operation with fetchAllPages = true to retrieve all products via the products_details query.Transform to hub contracts
CategoryIngest and ProductIngest contracts — normalizing IDs, names, parent references, and sort order.productStocks and product_price queries) and are planned for v2.| Node | Output shape |
|---|---|
Get Suppliers | Array of supplier objects |
Resolve VG SID | { vg_sid, vg_name } |
OPS: Get Categories | data.product_category.product_category[] |
Shape Categories | [{ external_id, name, parent_external_id, sort_order }] |
POST /ingest/categories | { sync_job_id, records_processed, status } |
ops-push.json — Push products to OPS storefront (Webhook)
ops-push.json — Push products to OPS storefront (Webhook)
Webhook trigger with customer_id
customer_id as a query parameter.Fetch markup payload per product
X-Ingest-Secret.Call OPS GraphQL mutations
setProduct— creates or updates the product shellsetProductPrice— creates a simple price band covering quantity 1 to 999,999
OPS Storefront credential in n8n must be updated manually when switching storefronts. It also uses category_id = 0 and size_id = 0 by default; update the Build OPS Inputs code node if your OPS instance requires valid IDs.ops-master-options-pull.json — Pull master options (Daily)
ops-master-options-pull.json — Pull master options (Daily)
Fetch paginated master options
getManyMasterOptions operation with full pagination enabled. Retrieves all master option fields and nested attributes[] arrays.Normalize to MasterOptionIngest
attributes[] array into the hub’s MasterOptionIngest contract.catalog-sync-weekly.json — Full catalog sync (Sunday 1 AM)
catalog-sync-weekly.json — Full catalog sync (Sunday 1 AM)
full_sellable import on every active supplier. Calls POST /api/suppliers/{id}/import with { "mode": "full_sellable" } for each supplier row returned by GET /api/suppliers. Designed to run overnight when OPS API rate limits are least congested.pricing-sync-daily.json — Delta pricing sync (Daily)
pricing-sync-daily.json — Delta pricing sync (Daily)
POST /api/suppliers/{id}/import with { "mode": "delta" }. Only requests pricing data that has changed since the last sync, keeping API call volume low.inventory-sync-hourly.json — Delta inventory sync (Hourly)
inventory-sync-hourly.json — Delta inventory sync (Hourly)
POST /api/suppliers/{id}/import with { "mode": "delta" } for each active supplier, refreshing stock levels every hour to keep storefronts accurate.closeouts-monthly.json — Closeouts sync (1st of month)
closeouts-monthly.json — Closeouts sync (1st of month)
POST /api/suppliers/{id}/import with { "mode": "closeouts" } to pull the current closeout catalog from each supplier.sanmar-sftp-pull.json — SanMar SFTP pull (Daily)
sanmar-sftp-pull.json — SanMar SFTP pull (Daily)
POST /api/ingest/{sid}/*. This workflow requires an SFTP credential configured in n8n in addition to the standard INGEST_SHARED_SECRET.Importing and activating workflows
Open the n8n editor
Import the workflow JSON
.json file from n8n-workflows/.Bind credentials
Failure modes
| Node in red | Error message | Cause | Fix |
|---|---|---|---|
Resolve VG SID | ”VG OPS supplier not seeded” | No vg-ops row in the database | Start FastAPI in development (it auto-creates the row), or run python backend/seed_demo.py |
Resolve VG SID | is_active = false | Supplier gate is closed | Run UPDATE suppliers SET is_active=true WHERE slug='vg-ops'; in Postgres |
| OPS node | 401 / 403 | Bad OAuth2 credentials | Re-enter the Client ID and Client Secret in the n8n credential editor |
POST /ingest/* | 401 “Invalid or missing X-Ingest-Secret” | INGEST_SHARED_SECRET mismatch between n8n and FastAPI | Compare docker exec api-hub-n8n-1 env | grep INGEST to .env; restart n8n |
POST /ingest/* | 409 “not active” | Supplier was deactivated after the workflow started | Run the SQL UPDATE above |
POST /ingest/* | 500 | FastAPI crashed | Check docker compose logs api for the uvicorn traceback |
INGEST_SHARED_SECRET in your .env file. If they differ, edit .env and restart: