{
  "$schema": "https://developers.openai.com/apps-sdk/schemas/chatgpt-app-submission.v1.json",
  "schema_version": 1,
  "app_info": {
    "display_name": "PHS Pallets",
    "subtitle": "Pallet quotes & tracking",
    "description": "PHS Pallets connects ChatGPT to the live PHS Inc plastic pallet catalog. Users can search ~100 pallet SKUs (stackable, rackable, nestable, heavy-duty, hygienic, export, spill-containment), see real best sellers with a buying guide, compare specs, prices and availability, and submit a real quote request to the PHS sales team — including estimated freight and lead time to any US ZIP code. Customers with a PHS Pallets account can sign in via an emailed one-time code (no passwords in chat) to view their quotes, orders, live shipment tracking with carrier timelines, and instantly reorder their last order at their previous pricing with a fresh freight estimate. No payments occur inside ChatGPT: quotes are reviewed by the PHS team and paid for via Stripe checkout in the PHS Pallets mobile app or emailed quote link. Physical goods only.",
    "category": "SHOPPING"
  },
  "tools": {
    "search_pallets": {
      "annotations": { "readOnlyHint": true, "destructiveHint": false, "idempotentHint": true, "openWorldHint": false },
      "justifications": {
        "read_only_justification": "Performs a GET against the PHS product catalog and filters results in memory; it never creates, updates, or deletes any data.",
        "open_world_justification": "Only communicates with the PHS Pallets first-party backend API; it does not access the public internet or any third-party systems.",
        "destructive_justification": "Purely a catalog search; it cannot modify or remove any records."
      }
    },
    "get_pallet_details": {
      "annotations": { "readOnlyHint": true, "destructiveHint": false, "idempotentHint": true, "openWorldHint": false },
      "justifications": {
        "read_only_justification": "Fetches a single product's specifications, price, and availability via GET; no state is changed.",
        "open_world_justification": "Only queries the PHS Pallets first-party backend API for one product record.",
        "destructive_justification": "Read-only product lookup; nothing is modified or deleted."
      }
    },
    "popular_pallets": {
      "annotations": { "readOnlyHint": true, "destructiveHint": false, "idempotentHint": true, "openWorldHint": false },
      "justifications": {
        "read_only_justification": "Reads best-selling products (aggregated from historical order data) plus a static buying guide via GET; no writes occur.",
        "open_world_justification": "Only queries the PHS Pallets first-party backend API; no third-party or open-web interaction.",
        "destructive_justification": "Read-only catalog recommendation; it cannot modify or remove any records."
      }
    },
    "request_quote": {
      "annotations": { "readOnlyHint": false, "destructiveHint": false, "idempotentHint": false, "openWorldHint": false },
      "justifications": {
        "read_only_justification": "Creates a new quote-request record in the PHS system (the same flow as the mobile app), sends the customer a confirmation email, and notifies the PHS sales team — therefore not read-only.",
        "open_world_justification": "Only writes to the PHS Pallets first-party backend via an internally-authenticated endpoint; no third-party or open-web interaction.",
        "destructive_justification": "Strictly additive: it inserts a new pending quote request. It cannot alter or delete existing quotes, orders, or accounts, and no payment is taken — every quote is manually reviewed by PHS staff."
      }
    },
    "request_login_code": {
      "annotations": { "readOnlyHint": false, "destructiveHint": false, "idempotentHint": false, "openWorldHint": false },
      "justifications": {
        "read_only_justification": "Generates and stores a hashed one-time sign-in code and emails it to the account holder — therefore not read-only. No passwords are ever collected in chat.",
        "open_world_justification": "Only calls the PHS Pallets first-party authentication endpoint over HTTPS; the code email is sent by the PHS backend itself.",
        "destructive_justification": "Strictly additive and rate-limited: it stores a short-lived (10-minute, single-use) code and never changes account data. The response is identical whether or not the account exists, preventing account enumeration."
      }
    },
    "login_with_code": {
      "annotations": { "readOnlyHint": false, "destructiveHint": false, "idempotentHint": false, "openWorldHint": false },
      "justifications": {
        "read_only_justification": "Exchanges the emailed one-time code for a session token, which creates a session and invalidates the code — therefore not read-only.",
        "open_world_justification": "Only calls the PHS Pallets first-party authentication endpoint over HTTPS.",
        "destructive_justification": "Issues a scoped session token only; codes are single-use with attempt limits, and no account data, passwords, or stored records are ever changed."
      }
    },
    "my_orders": {
      "annotations": { "readOnlyHint": true, "destructiveHint": false, "idempotentHint": true, "openWorldHint": false },
      "justifications": {
        "read_only_justification": "Lists the signed-in customer's own orders via GET using their session token; no writes occur.",
        "open_world_justification": "Only queries the PHS Pallets first-party backend, scoped to the authenticated customer's data.",
        "destructive_justification": "Read-only order listing; nothing can be modified or cancelled through this tool."
      }
    },
    "track_order": {
      "annotations": { "readOnlyHint": true, "destructiveHint": false, "idempotentHint": true, "openWorldHint": false },
      "justifications": {
        "read_only_justification": "Fetches status, carrier, ETA, and the shipment timeline for one of the customer's own orders via GET; no state is changed.",
        "open_world_justification": "Only queries the PHS Pallets first-party backend; freight data is already synced server-side, the tool itself contacts no third parties.",
        "destructive_justification": "Read-only tracking lookup; it cannot alter shipments or orders."
      }
    },
    "my_quotes": {
      "annotations": { "readOnlyHint": true, "destructiveHint": false, "idempotentHint": true, "openWorldHint": false },
      "justifications": {
        "read_only_justification": "Lists the signed-in customer's own quote requests and statuses via GET; no writes occur.",
        "open_world_justification": "Only queries the PHS Pallets first-party backend, scoped to the authenticated customer.",
        "destructive_justification": "Read-only quote listing; quotes cannot be changed or deleted through this tool."
      }
    },
    "reorder": {
      "annotations": { "readOnlyHint": false, "destructiveHint": false, "idempotentHint": false, "openWorldHint": false },
      "justifications": {
        "read_only_justification": "Creates a new quote record that re-prices the signed-in customer's own previous order (previous unit prices + fresh freight estimate) — therefore not read-only.",
        "open_world_justification": "Only writes to the PHS Pallets first-party backend, authenticated with the customer's own session token; no third-party or open-web interaction.",
        "destructive_justification": "Strictly additive: it inserts a new quote and never modifies or deletes the original order or any other record. No payment is taken in ChatGPT — the customer pays via Stripe checkout in the PHS app or emailed link, for physical goods only."
      }
    }
  },
  "test_cases": [
    {
      "description": "New-customer discovery: a first-time shopper asks for recommendations and gets PHS best sellers plus a buying guide.",
      "user_prompt": "I'm new to plastic pallets — what are the most popular options and which should I pick?",
      "tools_triggered": "popular_pallets",
      "expected_output": "PHS best-selling pallets with prices, availability and specs, plus a short buying guide matching pallet types (rackable, stackable, nestable, export, hygienic) to use cases, followed by a question about the shopper's use case.",
      "expected_output_url": null,
      "file_attachment_urls": null
    },
    {
      "description": "Spec deep-dive: after searching, the user asks for the full specification of one specific pallet.",
      "user_prompt": "Give me the full specs, load ratings and availability for the 48x40 rackable pallet you just found.",
      "tools_triggered": "search_pallets, get_pallet_details",
      "expected_output": "Full details for the selected product: dimensions, static/dynamic load, material, deck type, weight, price and availability.",
      "expected_output_url": null,
      "file_attachment_urls": null
    },
    {
      "description": "Quote request (core commerce flow): the user provides contact details and destination, and a real quote request is filed with the PHS sales team.",
      "user_prompt": "Request a quote for 200 units of that stackable pallet shipped to ZIP 75201. My name is Jane Doe, email jane.doe@example.com, company Acme Logistics.",
      "tools_triggered": "search_pallets, request_quote",
      "expected_output": "Confirmation with a quote number, pending status, itemized subtotal, estimated freight and lead time, plus a note that a confirmation email was sent and the PHS sales team will reply with final pricing. No payment is taken.",
      "expected_output_url": null,
      "file_attachment_urls": null
    },
    {
      "description": "Live shipment tracking: an existing PHS customer signs in with an emailed one-time code, lists their orders and tracks the most recent one end-to-end.",
      "user_prompt": "Sign in to my PHS Pallets account (email: info@phsinc.com — my emailed sign-in code is 847291) and track my most recent order — where is it and when will it arrive?",
      "tools_triggered": "login_with_code, my_orders, track_order",
      "expected_output": "Current status, carrier, tracking number, ETA and the shipment timeline (confirmed, processing, shipped, in transit, out for delivery, delivered) for the customer's own order.",
      "expected_output_url": null,
      "file_attachment_urls": null
    },
    {
      "description": "Instant reorder: a returning customer repeats their last order and gets an immediately payable quote at their previous pricing with fresh freight.",
      "user_prompt": "Reorder my last PHS pallet order. My account email is info@phsinc.com and my sign-in code is 847291.",
      "tools_triggered": "login_with_code, reorder",
      "expected_output": "After sign-in, a new quote at the customer's previous unit prices plus a fresh live freight estimate, marked ready to accept & pay, with a browser link to review it and a note that a payment-link email was sent. No payment occurs in ChatGPT.",
      "expected_output_url": null,
      "file_attachment_urls": null
    }
  ],
  "negative_test_cases": [
    {
      "description": "Package tracking for another retailer: sounds like order tracking, but it is not a PHS order — the app must not be invoked.",
      "user_prompt": "Can you track my Amazon package for me? It was supposed to arrive yesterday.",
      "tools_triggered": null,
      "expected_output": "ChatGPT answers normally (e.g., directing the user to Amazon's tracking) without invoking any PHS Pallets tools, since the shipment is not a PHS order.",
      "expected_output_url": null,
      "file_attachment_urls": null
    },
    {
      "description": "DIY upcycling of used wood pallets: mentions pallets, but the user wants craft advice, not to purchase new plastic pallets.",
      "user_prompt": "How do I build a garden planter out of old wooden pallets I found behind a store?",
      "tools_triggered": null,
      "expected_output": "ChatGPT gives general DIY guidance without invoking PHS Pallets tools — the user is not shopping for new plastic pallets.",
      "expected_output_url": null,
      "file_attachment_urls": null
    },
    {
      "description": "Competitor retail price check: pallet-purchase adjacent, but asks about another retailer's wooden pallet prices, not the PHS catalog.",
      "user_prompt": "What do wooden pallets cost at Home Depot right now?",
      "tools_triggered": null,
      "expected_output": "ChatGPT answers from general knowledge or suggests checking the retailer, without invoking PHS Pallets tools — the PHS catalog contains PHS plastic pallets, not other retailers' wood pallet pricing.",
      "expected_output_url": null,
      "file_attachment_urls": null
    }
  ]
}
