Developer

Premier Commerce API reference

These HTTP APIs are the integration surface. The application UI and an external MCP server call exactly the same endpoints, so nothing in the business logic is UI-specific.

Authentication

Every request is resolved through a single server-side identity abstraction (getRequestIdentity()), which returns the caller's subject, organization, role and permissions. Business logic never reads the browser's claim of who it is: organization IDs submitted by a client are ignored.

During development the identity travels in anx-demo-identityheader carrying the user id or the future Auth0 subject. Provenance headersx-sourceandx-source-client(or the equivalent body fields) record how the call originated.

When Auth0 is introduced, that function validates the access token instead and readssub, organization, permissions and client/actor claims. No endpoint or business rule changes.

GET
/api/account/context

Return the authenticated caller's purchasing context: user, organization, role, permissions.

Required permission: Any authenticated identity
logs authentication_context_received

Example response

{
  "user": {
    "id": "user_alex",
    "external_identity_id": "auth0|demo-alex",
    "name": "Alex Morgan",
    "email": "alex@northstarfinancial.example"
  },
  "organization": {
    "id": "org_northstar_us",
    "name": "Northstar Financial US",
    "account_tier": "Enterprise"
  },
  "role": "Procurement Manager",
  "permissions": ["catalog:read", "pricing:read", "quote:read", "quote:create"]
}
POST
/api/catalog/search

Return products the caller's organization is eligible to buy, priced against its enterprise agreement, with a deterministic requirement evaluation per product.

Required permission: catalog:read + pricing:read
logs catalog_searched

Example request

{
  "category": "Business Laptop",
  "quantity": 500,
  "requirements": {
    "minimum_ram_gb": 32,
    "minimum_storage_gb": 1000,
    "operating_system": "Windows 11 Pro",
    "screen_size_min": 14,
    "screen_size_max": 16,
    "maximum_delivery_days": 45
  },
  "budget": 1100000
}

Example response

{
  "organization": { "id": "org_northstar_us", "name": "Northstar Financial US", "account_tier": "Enterprise" },
  "result_count": 6,
  "eligible_count": 4,
  "results": [
    {
      "product": { "id": "prod_pb_7450", "sku": "P514260-ENT", "name": "Dell Pro 5 Series 14", "ram_gb": 32, "storage_gb": 1000, "screen_size": 14, "operating_system": "Windows 11 Pro" },
      "base_price": 2049,
      "contract_price": 1716,
      "discount_percentage": 16.25,
      "contract_name": "Northstar Financial Global Enterprise Agreement 2026",
      "quantity": 500,
      "pricing_math": {
        "base_total": 1024500,
        "contract_total": 858000,
        "contract_savings": 166500,
        "remaining_budget": 242000
      },
      "inventory": { "available_quantity": 1800, "estimated_delivery_days_min": 14, "estimated_delivery_days_max": 21 },
      "delivery_estimate": "14–21 days",
      "requirements_met": true,
      "requirement_checks": {
        "ram": { "required": "32 GB", "actual": "32 GB", "passed": true },
        "storage": { "required": "1 TB", "actual": "1 TB", "passed": true }
      },
      "requirement_mismatches": []
    }
  ]
}
GET
/api/products/:id

Full specifications, organization contract pricing, inventory, support options and quantity eligibility. Accepts a product id or SKU. Optional query params mirror the search requirements (quantity, budget, minimum_ram_gb, …).

Required permission: catalog:read
logs product_viewed

Example response

{
  "product": { "id": "prod_pb_7450", "sku": "P514260-ENT", "name": "Dell Pro 5 Series 14", "cpu": "Intel Core Ultra 7 365U vPro", "ports": "2x Thunderbolt 4 / USB-C, 2x USB-A, HDMI 2.1, RJ45" },
  "contract_price": 1716,
  "base_price": 2049,
  "inventory": { "available_quantity": 1800 },
  "delivery_estimate": "14–21 days",
  "support_options": "3-year enterprise support available",
  "requirements_met": true,
  "requirement_checks": { "quantity": { "required": "500 units", "actual": "1,800 units available", "passed": true } }
}
POST
/api/quotes/draft

Create a draft quote. Unit prices and totals are always recomputed from the organization's contract; prices supplied by the caller are ignored.

Required permission: catalog:read + pricing:read
logs quote_draft_created

Example request

{
  "items": [{ "product_id": "prod_pb_7450", "quantity": 500 }],
  "requested_delivery_date": "2027-01-31",
  "rfp_name": "FY27 Developer Laptop Refresh",
  "requirements_summary": "500 systems, minimum 32 GB RAM, minimum 1 TB SSD, Windows 11 Pro, delivery within 45 days.",
  "requirements": { "minimum_ram_gb": 32, "minimum_storage_gb": 1000, "quantity": 500, "budget": 1100000 },
  "notes": "Ship to Austin, Dallas and New York.",
  "budget": 1100000,
  "source": "AI_ASSISTED",
  "source_client": "ChatGPT"
}

Example response

{
  "id": "3f0f…",
  "quote_number": "Q-2026-00482",
  "status": "draft",
  "totals": {
    "base_total": 1024500,
    "contract_total": 858000,
    "contract_savings": 166500,
    "budget": 1100000,
    "remaining_budget": 242000
  },
  "items": [{ "sku": "P514260-ENT", "quantity": 500, "unit_price": 1716, "total_price": 858000 }]
}
POST
/api/quotes/:id/submit

Submit a formal quote request. The quote becomes visible in the seller console immediately. Permission is enforced server-side.

Required permission: quote:create
logs quote_submitted

Example request

{ "source": "AI_ASSISTED", "source_client": "ChatGPT" }

Example response

{
  "success": true,
  "quote_number": "Q-2026-00482",
  "status": "submitted",
  "message": "Your quote request has been submitted to the enterprise sales team."
}

// Caller without the permission (HTTP 403)
{
  "error": "INSUFFICIENT_PERMISSION",
  "message": "The current user may view pricing but cannot submit quote requests.",
  "required_permission": "quote:create"
}
GET
/api/quotes/:id

Quote details: buyer, organization, requirements, line items, computed totals and the activity timeline. The quote must belong to the caller's organization.

Required permission: quote:read (or seller/admin context via /api/seller/quotes/:id)

Example response

{
  "quote_number": "Q-2026-00482",
  "status": "submitted",
  "organization": { "id": "org_northstar_us", "name": "Northstar Financial US" },
  "buyer": { "name": "Alex Morgan", "role": "Procurement Manager" },
  "items": [{ "sku": "P514260-ENT", "quantity": 500, "unit_price": 1716, "total_price": 858000 }],
  "totals": { "contract_total": 858000, "contract_savings": 166500, "remaining_budget": 242000 },
  "activity": [{ "event_type": "quote_submitted", "source_client": "ChatGPT", "created_at": "…" }]
}
Error envelope

Shape

{
  "error": "INSUFFICIENT_PERMISSION",
  "message": "The current user may view pricing but cannot submit quote requests.",
  "required_permission": "quote:create"
}
UNAUTHORIZED401No caller identity was supplied.
FORBIDDEN403The resource belongs to another organization.
INSUFFICIENT_PERMISSION403The identity lacks the required permission (returned with required_permission).
INVALID_REQUEST400Malformed body, invalid quantity, or a quote that is no longer a draft.
PRODUCT_UNAVAILABLE409Product is inactive or not covered by the organization's contract.
QUANTITY_EXCEEDS_INVENTORY409Requested quantity exceeds available inventory.
QUOTE_NOT_FOUND404No quote exists with the supplied identifier.
INVALID_ORGANIZATION_CONTEXT403The caller has no valid purchasing organization.
BUDGET_EXCEEDED409Estimated total exceeds the stated budget.
NO_MATCHING_PRODUCTS200Search succeeded but nothing matched; returned alongside an empty result set.
MCP Integration

Premier Commerce hosts the Premier MCP server at /mcp. Each AI tool is a thin wrapper over the business operation below, so ChatGPT and this web application share one source of business truth.

get_account_contextGET /api/account/context
search_catalogPOST /api/catalog/search
get_product_detailsGET /api/products/:id
create_quote_draftPOST /api/quotes/draft
submit_quote_requestPOST /api/quotes/:id/submit
get_quote_statusGET /api/quotes/:id

Search and product results also carry a self-contained HTML view, so a client that supports inline app UI renders the catalog as image-led Dell product cards with requirement fit, specifications, availability, and lead time rather than plain text. Clients without that support fall back to the structured result.

Premier Commerce contributes no AI reasoning and hosts no conversational interface — ChatGPT is the AI client.

The catalog presented to ChatGPT is a simulated Dell Premier B2B catalog — real Dell product models and specifications, with accounts, contract pricing, inventory and imagery as demo data. Every card and account response carries a "simulated" marker so the demo is self-explanatory. The MCP endpoint is protected by Auth0 and never exposed as a public storefront.

Connect ChatGPT

ChatGPT app endpoint (Apps SDK — use this in ChatGPT)

https://mcp.a0demo.com/api/public/apps/mcp

Generic MCP endpoint (Claude, Cursor, CLI clients)

https://mcp.a0demo.com/mcp

Two endpoints serve the same six tools and the same commerce logic. The Apps SDK endpoint additionally publishes the card designs as listable UI templates (ui://premier-commerce/*, mime type text/html+skybridge) and links each tool to its template, which is what makes the cards render inline in ChatGPT.

Steps in ChatGPT

  1. Publish this project so the endpoint is reachable over HTTPS.
  2. In ChatGPT: Settings → Apps & Connectors → Advanced → enable Developer mode.
  3. Create a connector, paste the Apps SDK endpoint above, and allow the tools.
  4. Start a chat, enable the connector, and paste or attach the RFP.

Sharing: a developer-mode connector is bound to the account that created it. Anyone else who needs to run the demo adds the same endpoint in their own ChatGPT developer mode. Listing the app for all ChatGPT users requires OpenAI app submission and review, which is out of scope for this demo.

Card designs for the in-chat experience are compared at /dev/cards.

Auth0 protection (MCP + REST API)

Status: token verification active · issuer https://lab.a0demo.com/ · audience https://api.premier-commerce.demo · discovery https://lab.a0demo.com/.well-known/openid-configuration

Set AUTH0_DOMAIN and AUTH0_AUDIENCE as runtime secrets. Until both are set, the MCP server runs in development mode and resolves a demo buyer without a token. Once set, every call requires an Auth0 access token and the buyer is taken from the verified token subject.

Auth0 setup (identity only, no roles)

  1. Applications → APIs → Create API. Identifier is the audience, e.g. https://api.premier-commerce.demo. Signing RS256.
  2. Create an application for ChatGPT, allow its connector callback URL, and grant it access to that API.
  3. Add the client id and secret when creating the connector in ChatGPT.
  4. Roles, RBAC and permission scopes are optional — Premier Commerce enforces what a buyer may do.

Anyone who signs up in Auth0 can run the demo: the first verified call for an unknown token subject creates a Premier Commerce account in the default demo organization with full quote rights, recorded on users.auth0_subject so identity never depends on email. Existing buyers keep their own organization and pricing.

Web app sign-in (this site)

Status: development mode (demo identity, no login)

  1. Auth0 → Applications → Create Application → Single Page Application (a browser app cannot hold a client secret).
  2. Allowed Callback URLs, Allowed Logout URLs and Allowed Web Origins: this site's origin (both the preview URL and the published domain).
  3. Connections: enable Username-Password-Authentication and allow sign-ups so anyone can create an account.
  4. Add VITE_AUTH0_DOMAIN, VITE_AUTH0_CLIENT_ID and VITE_AUTH0_AUDIENCE as build secrets in Workspace Settings → Build Secrets (public OAuth identifiers; the Auth0 React SDK needs them at build time). The runtime secret form cannot store VITE_ variables because that prefix is reserved for build-time values.

With Auth0 configured, every /api/… call must carry a valid access token — the x-demo-identity header is ignored and unauthenticated calls, including the demo reset, return 401 UNAUTHORIZED.