CatalogHub offers three integration surfaces. Suppliers use the REST API or MCP to maintain their own catalogue and propose products to connected buyers. Buying organisations use the separate ordering agent API to search products and build orders.
Proposals are reviewed, never pushed
Each surface has its own credential. Choose by who is acting and where the integration runs.
Supplier catalogue API
Server-to-server integrations that run unattended, such as an ERP export job.
- Credential
- Supplier API key, sent as a bearer token
- Issued by
- A supplier manager or administrator, in Products › Supplier API access
- Acts as
- The supplier account that owns the key
- Lifetime
- 90 days by default; 1 to 365 days
- Endpoint
/api/supplier/v1
Supplier MCP tools
AI assistants and agent clients acting for a signed-in person.
- Credential
- OAuth 2.1 access token, obtained with PKCE
- Issued by
- The signed-in user, on the CatalogHub consent screen
- Acts as
- That user, within the suppliers they currently belong to
- Lifetime
- 1-hour access token; 30-day rotating refresh token
- Endpoint
/api/mcp
Ordering agent API
Purchasing agents acting for a buying organisation.
- Credential
- Ordering agent token
- Issued by
- A buying organisation administrator, in Shopping › Ordering agents
- Acts as
- The named ordering agent, within its organisation's limits
- Lifetime
- Set when the agent token is created
- Endpoint
/api/agent/v1
Credentials are not interchangeable
Supplier API access is off by default. Complete these steps once per supplier.
- Create a supplier account and verify its account email. A CatalogHub administrator then verifies the supplier's identity.
- Connect the supplier to each buying organisation and confirm the trade relationship through the existing supplier or administrator workflow.
- As a supplier manager or administrator, open Products › Supplier API access, enable access and create a named key with only the scopes you need. Copy the key when it is shown; it cannot be retrieved later.
- Store the key in your secret store and send it over HTTPS in the Authorization header. For MCP, connect your assistant instead and approve the requested scopes.
curl https://cataloghub.hopshq.com/api/supplier/v1/me \
-H "Authorization: Bearer $CATALOGHUB_SUPPLIER_KEY"Every supplier REST request carries a supplier API key as a bearer token.
Authorization: Bearer chsup_xxxxxxxx…- Keys expire after 90 days by default. You can choose between 1 and 365 days when creating a key.
- A supplier can have up to ten active keys. Give each integration its own named key so it can be revoked independently.
- CatalogHub stores only a hash of each key and a short display prefix. The full key is shown once, at creation.
- Every request re-checks that the supplier is verified, API access is enabled, the key owner's email is verified and the owner is still a supplier manager or administrator.
- Revoking a key or disabling API access stops it immediately. Re-enabling access does not restore old keys.
| Scope | Allows |
|---|---|
catalog:read | Read the supplier’s catalogue, private reference prices, archived products and allergen evidence revisions. |
catalog:write | Create, update, archive and restore products by SKU; submit supplier-attested allergen evidence. |
relationships:read | Read trade relationships, proposed offers and accepted buyer products and prices. |
catalog:publish | Propose products, buyer prices and allergen evidence for buyer review. Buyer declaration and Hops approval stay separate. |
All supplier endpoints are relative to the base path below and return JSON.
Base URLhttps://cataloghub.hopshq.com/api/supplier/v1
- POST/imports/file-previewScope
catalog:write - POST/imports/previewScope
catalog:write - POST/imports/commitScope
catalog:write - GET/trade-relationships/{relationshipId}/catalogueScope
relationships:read - PUT/trade-relationships/{relationshipId}/catalogueScope
catalog:write - GET/trade-relationships/{relationshipId}/catalogue/previewScope
relationships:read - POST/trade-relationships/{relationshipId}/catalogue/publicationsScope
catalog:publish - GET/products/{productId}/allergen-evidence
Read immutable allergen evidence revisions for a supplier product.
Scopecatalog:read - POST/products/{productId}/allergen-evidenceScope
catalog:write - POST/trade-relationships/{relationshipId}/allergen-publications
Share selected revisions for the buyer’s declaration review.
Scopecatalog:publish - GET/me
Returns the supplier ID and the key's scopes.
Scopecatalog:read - Scope
catalog:read - GET/products?visibility=public
Lists the supplier's active public listings, with its private reference prices.
Scopecatalog:read - Scope
catalog:write - GET/trade-relationships
Lists trade relationships, buyer identities, currency, status and product counts.
Scoperelationships:read - GET/trade-relationships/{relationshipId}/products
Returns the latest proposed offers and the accepted buyer products and prices, separately.
Scoperelationships:read - POST/trade-relationships/{relationshipId}/publications
Creates a buyer catalogue review and schedules the review notification.
Scopecatalog:publish
Exact request and response schemas are published in the supplier OpenAPI specification, linked under Resources.
List endpoints use offset pagination.
limitaccepts 1 to 100 and defaults to 100.offsetdefaults to 0.- Catalogue and relationship lists return total, limit and offset. Keep requesting until offset reaches total.
- Relationship product reads return offers and accepted products with separate totals, both paged by the same offset. Continue until both totals are exhausted.
Read the supplier's own catalogue to reconcile it with your source system.
- Without a filter, the response includes private and archived products and the supplier's private reference prices.
- With visibility=public, only active products explicitly marked public are returned. Private reference prices are still included because the caller is the supplier.
curl "https://cataloghub.hopshq.com/api/supplier/v1/products?limit=100&offset=0" \
-H "Authorization: Bearer $CATALOGHUB_SUPPLIER_KEY"
curl "https://cataloghub.hopshq.com/api/supplier/v1/products?visibility=public&limit=100&offset=100" \
-H "Authorization: Bearer $CATALOGHUB_SUPPLIER_KEY"Send the complete intended state of each product. Products are matched by SKU.
- SKUs are supplier-scoped, trimmed and case-insensitive. Updating, archiving or restoring a SKU keeps its product ID. Changing a SKU creates another product; archive the previous SKU if needed.
- Fields replace the stored product. Omitted optional description, pack, unit and sizing fields are cleared.
- Omitted public visibility becomes private, and omitted active status becomes active. Products you do not send are left unchanged.
- A batch holds up to 500 products with unique SKUs. Any invalid product rejects the whole batch, so nothing is partially written.
- Upserting never changes any buyer's catalogue.
Required
skuproductNamecategorybasePriceOptional
descriptionunitOfMeasurepackSizeisPublicisActivesizingmultipleL1ContainermultipleL1Number- Prices are non-negative JSON numbers with at most two decimal places, up to 99,999,999.99.
- Reference and negotiated prices are net prices per ordering unit. The currency of a buyer-specific price comes from the buying organisation in that relationship.
- Category is the supplier's own text. During review it is matched to the receiving organisation's active category taxonomy.
- Structured sizing is optional. Use consistent type and unit pairs (Unit with Units, Weight with Grams, Volume with Millilitres) and the canonical container names.
- The outer container name and its positive whole-number count must be supplied together.
curl -X PUT https://cataloghub.hopshq.com/api/supplier/v1/products \
-H "Authorization: Bearer $CATALOGHUB_SUPPLIER_KEY" \
-H "Content-Type: application/json" \
-d @products.jsonThe response returns the stored products, with stable product IDs and prices as decimal strings. Request bodies are limited to 2 MiB.
Relationships connect the supplier to buying organisations. Use them to choose where to propose products and to see what each buyer has accepted.
- The relationship list includes the buyer, currency, lifecycle status and product counts.
- A relationship's products separate the latest proposed offers from the products and prices the buyer has accepted.
- Each buyer receives its own negotiated prices; proposing to one buyer does not affect another.
curl "https://cataloghub.hopshq.com/api/supplier/v1/trade-relationships?limit=100&offset=0" \
-H "Authorization: Bearer $CATALOGHUB_SUPPLIER_KEY"
curl "https://cataloghub.hopshq.com/api/supplier/v1/trade-relationships/<relationship-id>/products?limit=100&offset=0" \
-H "Authorization: Bearer $CATALOGHUB_SUPPLIER_KEY"A publication sends selected products at buyer-specific net prices to one buying organisation as a catalogue review.
- The supplier must be verified.
- The relationship must be confirmed:
supplier_confirmedadmin_confirmed - Its status must be one of:
approvedterms_setcatalogue_enabledordering_enabled - Every product must belong to the calling supplier and be active.
- Prospects, inferred or unconfirmed relationships, suspended relationships and company-only relationships cannot receive proposals.
- An idempotency key is required. Use 8 to 120 letters, numbers, dots, underscores, colons or hyphens.
- A new proposal returns HTTP 201 with publication, catalogue request and submission IDs and an initial pending review status.
- An exact retry returns HTTP 200 with the same IDs and marks the result as idempotent. Retries are safe even when they run concurrently.
- Reusing a key with different items, prices or notes returns HTTP 409.
- Item order does not affect identity. The returned status describes the initial proposal only; read the relationship's products for the current review status.
curl -X POST https://cataloghub.hopshq.com/api/supplier/v1/trade-relationships/<relationship-id>/publications \
-H "Authorization: Bearer $CATALOGHUB_SUPPLIER_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: proposal-00000001" \
-d '{
"items": [{ "productId": "<product-id-from-upsert>", "price": 4.25 }],
"notes": "New products and agreed prices for your review."
}'- Product data and prices are copied into the review. Later catalogue edits do not change it.
- The buyer reviews each product; their decisions stay staged until the review is completed.
- Completing the review saves the accepted products and prices to the buyer's catalogue.
- Publishing to Hops remains a separate step and still requires the supplier link, category and account mapping, tax mapping and sizing checks.
No automatic Hops publication
The primary catalogue holds every supplier product. Mark selected items isPublic for the public base catalogue; basePrice is standard RRP excluding tax per ordering unit. Anonymous public discovery still excludes prices. A customer catalogue stores selected primary products and one percentage-off-RRP tier for a confirmed trade relationship.
Send revision 0 to create; use the returned revision for edits. discountedProductIds: null discounts all shared items; an array discounts only that subset. Other shared items keep RRP. Use 0–100%, at most two decimal places. Prices round half up to cents. There are no quantity tiers or currency conversions.
{
"revision": 0,
"name": "Customer standard",
"productIds": [
"<shared-product-id>",
"<second-shared-product-id>"
],
"discountPercent": 10,
"discountedProductIds": [
"<shared-product-id>"
]
}curl -X PUT https://cataloghub.hopshq.com/api/supplier/v1/trade-relationships/<relationship-id>/catalogue \
-H "Authorization: Bearer $CATALOGHUB_SUPPLIER_KEY" -H "Content-Type: application/json" -d @customer-catalogue.json
curl https://cataloghub.hopshq.com/api/supplier/v1/trade-relationships/<relationship-id>/catalogue/preview \
-H "Authorization: Bearer $CATALOGHUB_SUPPLIER_KEY"
curl -X POST https://cataloghub.hopshq.com/api/supplier/v1/trade-relationships/<relationship-id>/catalogue/publications \
-H "Authorization: Bearer $CATALOGHUB_SUPPLIER_KEY" -H "Content-Type: application/json" -H "Idempotency-Key: customer-00000001" \
-d '{"previewHash":"<hash-from-preview>"}'Customer catalogues and pricing tiers
POST imports/file-preview with a CSV/XLS/XLSX file, or imports/preview with JSON products. Neither saves products. Ambiguous file headers return mappingRequired; resubmit a mapping from source headers to canonical fields. Correct returned products and row issues, then POST imports/commit with baseline, products and Idempotency-Key. Omitted fields retain existing metadata and visibility; new products default private. Stale baselines return 409. Commit is atomic and exact retries return the original products.
curl -X POST https://cataloghub.hopshq.com/api/supplier/v1/imports/file-preview \
-H "Authorization: Bearer $CATALOGHUB_SUPPLIER_KEY" -F 'file=@supplier-catalogue.csv'
curl -X POST https://cataloghub.hopshq.com/api/supplier/v1/imports/commit \
-H "Authorization: Bearer $CATALOGHUB_SUPPLIER_KEY" -H "Content-Type: application/json" -H "Idempotency-Key: import-00000001" \
-d @reviewed-import.jsonStore reusable supplier-attested evidence against an exact supplier product. Supplier identity verification does not independently verify allergen content. Each immutable revision records the source reference, exact wording, submitting account and SHA-256 hash.
Allergen evidence and buyer declarations
curl -X POST https://cataloghub.hopshq.com/api/supplier/v1/products/<product-id>/allergen-evidence \
-H "Authorization: Bearer $CATALOGHUB_SUPPLIER_KEY" \
-H "Idempotency-Key: allergen-00000001" \
-H "Content-Type: application/json" \
-d @allergen-evidence.json{
"supplierAttested": true,
"source": {
"reference": "<supplier-specification-reference>",
"description": "<source-description>",
"issuedOn": "2026-10-14"
},
"completeness": "partial",
"statements": [
{
"allergenCode": "milk",
"statementType": "contains",
"exactText": "<exact-source-wording>"
}
]
}After the buyer accepts a catalogue item, share a selected evidence revision with its exact accepted product ID. Up to 100 items per evidence publication. The buyer opens Supplier requests in Allergens, reviews the source and product match, confirms statements and closes the declaration. Hops then requires its separate mapped-product preview and human approval.
{
"items": [
{
"productId": "<supplier-product-id>",
"revisionId": "<evidence-revision-id>",
"restaurantCatalogItemId": "<accepted-buyer-product-id>"
}
]
}No automatic Hops publication
Anyone can discover a verified supplier's public listings without credentials.
- No authentication is required. Pagination works the same way as the supplier API.
- Only active products explicitly marked public are returned, and every price field is excluded.
- Public visibility is optional. Private products can still be proposed to connected buyers.
curl "https://cataloghub.hopshq.com/api/public/suppliers/<supplier-id>/catalog?limit=100&offset=0"Errors include an English message, a stable machine code and a message key for localised display. Handle them by code, not by message text.
| Status | Meaning |
|---|---|
400 | Invalid fields, category or sizing mapping, or a missing or malformed idempotency key. |
401 | The key is missing, invalid, expired, revoked or no longer authorised. |
403 | The key lacks the required scope, or the supplier is not verified or API access is disabled. |
404 | The relationship or product does not exist for this supplier. |
409 | The relationship is inactive, an assignment conflicts, or an idempotency key was reused with different content. |
413 | The request body is larger than 2 MiB. |
429 | Rate limit exceeded. Wait and retry with backoff. |
- Up to 500 products per upsert.
- Request bodies up to 2 MiB.
- Up to 120 requests per minute on the bearer API.
- Up to 100 results per page.
- Authenticated responses are sent with Cache-Control: no-store. Do not cache them in shared caches.
The CatalogHub Model Context Protocol server lets AI assistants read and update a supplier catalogue and propose products, on behalf of the person who connected it.
- Endpoint:
https://cataloghub.hopshq.com/api/mcp - Streamable HTTP with stateless JSON responses. Send JSON-RPC 2.0 requests with POST.
- Call it from your assistant or server. Browser requests from other websites are rejected.
- Tools apply the same validation, limits and review workflow as the REST API.
curl https://cataloghub.hopshq.com/api/mcp \
-H "Authorization: Bearer $CATALOGHUB_OAUTH_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d @request.jsonMost MCP clients perform discovery, sign-in, initialisation and tool listing automatically when you add the endpoint URL. The raw requests are shown for clients you build yourself.
MCP access is bound to a CatalogHub user. The assistant never sees the user's password or a supplier API key.
- Discover the authorisation server from the protected resource metadata.
- Register your client dynamically with its redirect URIs, or reuse an existing registration.
- Create a random code verifier and send its SHA-256 challenge (S256) with the requested scopes and the MCP resource.
- The user signs in to CatalogHub and approves or declines the requested access on the consent screen.
- Exchange the authorisation code and verifier for an access token and refresh token.
- Send the access token as a bearer token to the MCP endpoint, refresh it when it expires, and revoke it when access is no longer needed.
curl https://cataloghub.hopshq.com/.well-known/oauth-protected-resource/api/mcp
curl https://cataloghub.hopshq.com/.well-known/oauth-authorization-server- Access tokens are valid for 1 hour.
- Refresh tokens last 30 days and rotate: each refresh returns a new refresh token. Reusing an old refresh token revokes the connection.
- Disconnect from the Connect an AI agent panel in CatalogHub, or revoke a token at the revocation endpoint.
- Redirect URIs must use HTTPS, HTTP on a loopback address, or a native app's private scheme.
Request only the scopes the assistant needs. Each OAuth scope mirrors a supplier API key scope.
| OAuth scope | REST key scope | Allows |
|---|---|---|
supplier:catalog:read | catalog:read | Read the supplier’s catalogue, private reference prices, archived products and allergen evidence revisions. |
supplier:catalog:write | catalog:write | Create, update, archive and restore products by SKU; submit supplier-attested allergen evidence. |
supplier:relationships:read | relationships:read | Read trade relationships, proposed offers and accepted buyer products and prices. |
supplier:catalog:publish | catalog:publish | Propose products, buyer prices and allergen evidence for buyer review. Buyer declaration and Hops approval stay separate. |
The consent screen shows read access, product changes and buyer proposals as separate choices, with changes and proposals unchecked by default. Existing connections never gain new scopes automatically; reconnect to grant supplier permissions.
Every supplier tool takes a supplier_id. First call cataloghub_list_my_accounts, granted with the feedback scope, to find the suppliers the signed-in user can act for. tools/list returns only the tools your token’s scopes allow. Argument names use snake_case; product and item objects use the same camelCase fields as the REST API.
Lists the buying organisations, suppliers and reseller accounts the signed-in user can use, with their role in each. Use it to find supplier IDs.
- OAuth scope
feedback
This tool takes no arguments.
{
"jsonrpc": "2.0",
"id": 10,
"method": "tools/call",
"params": {
"name": "cataloghub_list_my_accounts",
"arguments": {}
}
}Lists the supplier's catalogue, one page at a time, including private reference prices.
- OAuth scope
supplier:catalog:read- REST equivalent
GET /api/supplier/v1/products
| Argument | Required | Description |
|---|---|---|
supplier_id | Required | ID of a supplier the signed-in user currently belongs to. Product changes and proposals need a manager or administrator. |
limit | Optional | Page size, from 1 to 100. Defaults to 100. |
offset | Optional | Number of results to skip. Defaults to 0. |
visibility | Optional | all (the default) returns the full catalogue; public returns only active public listings. |
{
"jsonrpc": "2.0",
"id": 11,
"method": "tools/call",
"params": {
"name": "cataloghub_list_supplier_catalog",
"arguments": {
"supplier_id": "<supplier-id>",
"limit": 100,
"offset": 0,
"visibility": "public"
}
}
}Creates or updates up to 500 products by SKU in one atomic batch. Buyer catalogues do not change.
- OAuth scope
supplier:catalog:write- REST equivalent
PUT /api/supplier/v1/products
| Argument | Required | Description |
|---|---|---|
supplier_id | Required | ID of a supplier the signed-in user currently belongs to. Product changes and proposals need a manager or administrator. |
products | Required | Array of up to 500 product objects, with the same fields as the REST upsert. |
{
"jsonrpc": "2.0",
"id": 12,
"method": "tools/call",
"params": {
"name": "cataloghub_upsert_supplier_products",
"arguments": {
"supplier_id": "<supplier-id>",
"products": [
{
"sku": "ONIONS-1KG",
"productName": "Onions 1kg",
"description": "Fresh onions",
"category": "Vegetables",
"unitOfMeasure": "kg",
"packSize": 1,
"basePrice": 9,
"isPublic": true,
"isActive": true,
"sizing": {
"baseUomType": "Weight",
"baseUom": "Grams",
"baseNumber": 1000,
"baseContainer": "Bag"
}
}
]
}
}
}Lists the supplier's trade relationships with buyer, currency, status and product counts.
- OAuth scope
supplier:relationships:read- REST equivalent
GET /api/supplier/v1/trade-relationships
| Argument | Required | Description |
|---|---|---|
supplier_id | Required | ID of a supplier the signed-in user currently belongs to. Product changes and proposals need a manager or administrator. |
limit | Optional | Page size, from 1 to 100. Defaults to 100. |
offset | Optional | Number of results to skip. Defaults to 0. |
{
"jsonrpc": "2.0",
"id": 13,
"method": "tools/call",
"params": {
"name": "cataloghub_list_supplier_trade_relationships",
"arguments": {
"supplier_id": "<supplier-id>",
"limit": 100,
"offset": 0
}
}
}Returns the proposed offers and the accepted products and prices for one relationship.
- OAuth scope
supplier:relationships:read- REST equivalent
GET /api/supplier/v1/trade-relationships/{relationshipId}/products
| Argument | Required | Description |
|---|---|---|
supplier_id | Required | ID of a supplier the signed-in user currently belongs to. Product changes and proposals need a manager or administrator. |
relationship_id | Required | Trade relationship ID from the relationship list. |
limit | Optional | Page size, from 1 to 100. Defaults to 100. |
offset | Optional | Number of results to skip. Defaults to 0. |
{
"jsonrpc": "2.0",
"id": 14,
"method": "tools/call",
"params": {
"name": "cataloghub_get_supplier_trade_catalog",
"arguments": {
"supplier_id": "<supplier-id>",
"relationship_id": "<relationship-id>",
"limit": 100,
"offset": 0
}
}
}Proposes products at buyer-specific net prices for the buyer's review. Requires an idempotency key.
- OAuth scope
supplier:catalog:publish- REST equivalent
POST /api/supplier/v1/trade-relationships/{relationshipId}/publications
| Argument | Required | Description |
|---|---|---|
supplier_id | Required | ID of a supplier the signed-in user currently belongs to. Product changes and proposals need a manager or administrator. |
relationship_id | Required | Trade relationship ID from the relationship list. |
items | Required | Array of objects with productId and the proposed net price per ordering unit. |
notes | Optional | Optional message shown to the buyer with the review. |
idempotency_key | Required | 8 to 120 letters, numbers, dots, underscores, colons or hyphens. Reuse it only to retry the identical proposal. |
{
"jsonrpc": "2.0",
"id": 15,
"method": "tools/call",
"params": {
"name": "cataloghub_publish_supplier_products",
"arguments": {
"supplier_id": "<supplier-id>",
"relationship_id": "<relationship-id>",
"items": [
{
"productId": "<product-id-from-upsert>",
"price": 4.25
}
],
"notes": "New products and agreed prices for your review.",
"idempotency_key": "proposal-00000001"
}
}
}Read immutable allergen evidence revisions for a supplier product.
- OAuth scope
supplier:catalog:read- REST equivalent
GET /api/supplier/v1/products/{productId}/allergen-evidence
| Argument | Required | Description |
|---|---|---|
supplier_id | Required | ID of a supplier the signed-in user currently belongs to. Product changes and proposals need a manager or administrator. |
product_id | Required | Exact supplier product identifier returned by the catalogue. |
limit | Optional | Page size, from 1 to 100. Defaults to 100. |
offset | Optional | Number of results to skip. Defaults to 0. |
{
"jsonrpc": "2.0",
"id": 16,
"method": "tools/call",
"params": {
"name": "cataloghub_list_supplier_allergen_evidence",
"arguments": {
"supplier_id": "<supplier-id>",
"product_id": "<product-id>",
"limit": 100,
"offset": 0
}
}
}Submit a new supplier-attested allergen evidence revision.
- OAuth scope
supplier:catalog:write- REST equivalent
POST /api/supplier/v1/products/{productId}/allergen-evidence
| Argument | Required | Description |
|---|---|---|
supplier_id | Required | ID of a supplier the signed-in user currently belongs to. Product changes and proposals need a manager or administrator. |
product_id | Required | Exact supplier product identifier returned by the catalogue. |
evidence | Required | Source reference, exact statements, completeness and explicit supplier attestation. |
idempotency_key | Required | 8 to 120 letters, numbers, dots, underscores, colons or hyphens. Reuse it only to retry the identical proposal. |
{
"jsonrpc": "2.0",
"id": 17,
"method": "tools/call",
"params": {
"name": "cataloghub_submit_supplier_allergen_evidence",
"arguments": {
"supplier_id": "<supplier-id>",
"product_id": "<product-id>",
"evidence": {
"supplierAttested": true,
"source": {
"reference": "<supplier-specification-reference>",
"description": "<source-description>",
"issuedOn": "2026-10-14"
},
"completeness": "partial",
"statements": [
{
"allergenCode": "milk",
"statementType": "contains",
"exactText": "<exact-source-wording>"
}
]
},
"idempotency_key": "allergen-00000001"
}
}
}Share selected revisions for the buyer’s declaration review.
- OAuth scope
supplier:catalog:publish- REST equivalent
POST /api/supplier/v1/trade-relationships/{relationshipId}/allergen-publications
| Argument | Required | Description |
|---|---|---|
supplier_id | Required | ID of a supplier the signed-in user currently belongs to. Product changes and proposals need a manager or administrator. |
relationship_id | Required | Trade relationship ID from the relationship list. |
items | Required | Exact supplier product, evidence revision and accepted buyer product identifiers. |
idempotency_key | Required | 8 to 120 letters, numbers, dots, underscores, colons or hyphens. Reuse it only to retry the identical proposal. |
{
"jsonrpc": "2.0",
"id": 18,
"method": "tools/call",
"params": {
"name": "cataloghub_publish_supplier_allergen_evidence",
"arguments": {
"supplier_id": "<supplier-id>",
"relationship_id": "<relationship-id>",
"items": [
{
"productId": "<supplier-product-id>",
"revisionId": "<evidence-revision-id>",
"restaurantCatalogItemId": "<accepted-buyer-product-id>"
}
],
"idempotency_key": "allergen-00000002"
}
}
}Read customer catalogue
- OAuth scope
supplier:relationships:read- REST equivalent
GET /api/supplier/v1/trade-relationships/{relationshipId}/catalogue
| Argument | Required | Description |
|---|---|---|
supplier_id | Required | ID of a supplier the signed-in user currently belongs to. Product changes and proposals need a manager or administrator. |
relationship_id | Required | Trade relationship ID from the relationship list. |
{
"jsonrpc": "2.0",
"id": 19,
"method": "tools/call",
"params": {
"name": "cataloghub_get_customer_catalogue",
"arguments": {
"supplier_id": "<supplier-id>",
"relationship_id": "<relationship-id>"
}
}
}Save customer selection and tier
- OAuth scope
supplier:catalog:write- REST equivalent
PUT /api/supplier/v1/trade-relationships/{relationshipId}/catalogue
| Argument | Required | Description |
|---|---|---|
supplier_id | Required | ID of a supplier the signed-in user currently belongs to. Product changes and proposals need a manager or administrator. |
relationship_id | Required | Trade relationship ID from the relationship list. |
catalogue | Required | Saved selection and percentage tier, including the last revision. |
{
"jsonrpc": "2.0",
"id": 20,
"method": "tools/call",
"params": {
"name": "cataloghub_save_customer_catalogue",
"arguments": {
"supplier_id": "<supplier-id>",
"relationship_id": "<relationship-id>",
"catalogue": {
"revision": 0,
"name": "Customer standard",
"productIds": [
"<product-id>"
],
"discountPercent": 10,
"discountedProductIds": null
}
}
}
}Preview customer prices
- OAuth scope
supplier:relationships:read- REST equivalent
GET /api/supplier/v1/trade-relationships/{relationshipId}/catalogue/preview
| Argument | Required | Description |
|---|---|---|
supplier_id | Required | ID of a supplier the signed-in user currently belongs to. Product changes and proposals need a manager or administrator. |
relationship_id | Required | Trade relationship ID from the relationship list. |
{
"jsonrpc": "2.0",
"id": 21,
"method": "tools/call",
"params": {
"name": "cataloghub_preview_customer_catalogue",
"arguments": {
"supplier_id": "<supplier-id>",
"relationship_id": "<relationship-id>"
}
}
}Propose saved catalogue for buyer review
- OAuth scope
supplier:catalog:publish- REST equivalent
POST /api/supplier/v1/trade-relationships/{relationshipId}/catalogue/publications
| Argument | Required | Description |
|---|---|---|
supplier_id | Required | ID of a supplier the signed-in user currently belongs to. Product changes and proposals need a manager or administrator. |
relationship_id | Required | Trade relationship ID from the relationship list. |
previewHash | Required | Exact hash returned by the price preview. |
notes | Optional | Optional message shown to the buyer with the review. |
idempotency_key | Required | 8 to 120 letters, numbers, dots, underscores, colons or hyphens. Reuse it only to retry the identical proposal. |
{
"jsonrpc": "2.0",
"id": 22,
"method": "tools/call",
"params": {
"name": "cataloghub_publish_customer_catalogue",
"arguments": {
"supplier_id": "<supplier-id>",
"relationship_id": "<relationship-id>",
"previewHash": "<hash-from-preview>",
"idempotency_key": "customer-00000001"
}
}
}Preview import without saving
- OAuth scope
supplier:catalog:write- REST equivalent
POST /api/supplier/v1/imports/preview
| Argument | Required | Description |
|---|---|---|
supplier_id | Required | ID of a supplier the signed-in user currently belongs to. Product changes and proposals need a manager or administrator. |
products | Required | Array of up to 500 product objects, with the same fields as the REST upsert. |
{
"jsonrpc": "2.0",
"id": 23,
"method": "tools/call",
"params": {
"name": "cataloghub_preview_supplier_import",
"arguments": {
"supplier_id": "<supplier-id>",
"products": [
{
"sku": "ONIONS-1KG",
"productName": "Onions 1kg",
"description": "Fresh onions",
"category": "Vegetables",
"unitOfMeasure": "kg",
"packSize": 1,
"basePrice": 9,
"isPublic": true,
"isActive": true,
"sizing": {
"baseUomType": "Weight",
"baseUom": "Grams",
"baseNumber": 1000,
"baseContainer": "Bag"
}
}
]
}
}
}Save reviewed import
- OAuth scope
supplier:catalog:write- REST equivalent
POST /api/supplier/v1/imports/commit
| Argument | Required | Description |
|---|---|---|
supplier_id | Required | ID of a supplier the signed-in user currently belongs to. Product changes and proposals need a manager or administrator. |
baseline | Required | Catalogue baseline returned by the import preview. |
products | Required | Array of up to 500 product objects, with the same fields as the REST upsert. |
idempotency_key | Required | 8 to 120 letters, numbers, dots, underscores, colons or hyphens. Reuse it only to retry the identical proposal. |
{
"jsonrpc": "2.0",
"id": 24,
"method": "tools/call",
"params": {
"name": "cataloghub_commit_supplier_import",
"arguments": {
"supplier_id": "<supplier-id>",
"baseline": "<baseline-from-preview>",
"products": [
{
"sku": "ONIONS-1KG",
"productName": "Onions 1kg",
"description": "Fresh onions",
"category": "Vegetables",
"unitOfMeasure": "kg",
"packSize": 1,
"basePrice": 9,
"isPublic": true,
"isActive": true,
"sizing": {
"baseUomType": "Weight",
"baseUom": "Grams",
"baseNumber": 1000,
"baseContainer": "Bag"
}
}
],
"idempotency_key": "import-00000001"
}
}
}MCP tools act as the signed-in user, never as a broader service account.
- Tools work only for suppliers the user currently belongs to directly. Reading needs any verified member; product changes and proposals need a manager or administrator.
- Supplier tools require OAuth. Supplier REST keys and personal MCP access tokens cannot use them.
- Membership, roles and supplier status are checked live on every call. Removing a user from a supplier stops access immediately, even if their token has not expired.
- Reseller access and support impersonation never grant supplier tool authority, and administrators’ view-as sessions do not carry over to tokens.
- The existing rules still apply: the user’s email and the supplier must be verified, and Supplier API access must be enabled.
- Proposals follow the same relationship eligibility, idempotency and buyer review rules as the REST API.
- No tool publishes to Hops or changes a buyer's live catalogue directly.
Buying organisations can let a purchasing agent search their suppliers' products, build baskets and, when permitted, submit orders. This API is separate from the supplier catalogue API.
- A buying organisation administrator creates the agent and gives it a dedicated ordering agent token.
- Agents either propose baskets for people to review and send, or submit orders within spending limits and approval thresholds.
- Agents see only suppliers and products that the organisation can already order from.
REST only
curl "https://cataloghub.hopshq.com/api/agent/v1/products?q=olive%20oil" \
-H "Authorization: Bearer $CATALOGHUB_ORDERING_AGENT_TOKEN"Machine-readable references for code generation, testing and AI assistants.
Supplier catalogue API and MCP
Ordering agent API
Specifications and protocol identifiers are published in English so that they match the API exactly.