{
  "info": {
    "_postman_id": "f0ee9c21-b279-4f14-9004-2a4e452fe857",
    "name": "Tetrees EX API — Seller & Entitled Delivery",
    "description": "Supported ordinary API-token workflow. Create the token in Account > API access, set the collection variable `token`, and begin with Token status. The seller-prep request is guarded and cannot run until `allowPointSpend` is explicitly set to RUN_SELLER_PREP.",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "auth": {
    "type": "bearer",
    "bearer": [{ "key": "token", "value": "{{token}}", "type": "string" }]
  },
  "variable": [
    { "key": "baseUrl", "value": "https://ex.tetrees.ai", "type": "string" },
    { "key": "token", "value": "", "type": "string" },
    { "key": "productId", "value": "", "type": "string" },
    { "key": "productSlug", "value": "", "type": "string" },
    { "key": "tier", "value": "verified_listing", "type": "string" },
    { "key": "expectedVersion", "value": "", "type": "string" },
    { "key": "expectedPoints", "value": "", "type": "string" },
    { "key": "allowPointSpend", "value": "", "type": "string" }
  ],
  "item": [
    {
      "name": "1. Authentication",
      "item": [
        {
          "name": "Token status",
          "request": {
            "method": "GET",
            "header": [{ "key": "Accept", "value": "application/json" }],
            "url": { "raw": "{{baseUrl}}/api/auth/api-token-status", "host": ["{{baseUrl}}"], "path": ["api", "auth", "api-token-status"] },
            "description": "Run first. A valid txk_ token returns authenticated=true and its effective permissions."
          },
          "event": [{ "listen": "test", "script": { "exec": ["pm.test('Token is authenticated', function () {", "  pm.response.to.have.status(200);", "  pm.expect(pm.response.json().authenticated).to.eql(true);", "});"] } }]
        }
      ]
    },
    {
      "name": "2. Discovery",
      "item": [
        {
          "name": "Browse verified products",
          "request": {
            "method": "GET",
            "header": [{ "key": "Accept", "value": "application/json" }],
            "url": {
              "raw": "{{baseUrl}}/api/catalog/products?q=payment&verified=true&sort=top_rated&page_size=12",
              "host": ["{{baseUrl}}"],
              "path": ["api", "catalog", "products"],
              "query": [
                { "key": "q", "value": "payment" },
                { "key": "verified", "value": "true" },
                { "key": "sort", "value": "top_rated" },
                { "key": "page_size", "value": "12" }
              ]
            }
          },
          "event": [{ "listen": "test", "script": { "exec": ["pm.test('Catalog response has pagination', function () {", "  pm.response.to.have.status(200);", "  const body = pm.response.json();", "  pm.expect(body.products).to.be.an('array');", "  pm.expect(body.pagination).to.be.an('object');", "});"] } }]
        },
        {
          "name": "Smart search",
          "request": {
            "method": "POST",
            "header": [{ "key": "Content-Type", "value": "application/json" }],
            "body": { "mode": "raw", "raw": "{\n  \"query\": \"payment processing integration for a mobile app\"\n}" },
            "url": { "raw": "{{baseUrl}}/api/catalog/smart-search", "host": ["{{baseUrl}}"], "path": ["api", "catalog", "smart-search"] }
          }
        },
        {
          "name": "Product detail by slug",
          "request": {
            "method": "GET",
            "header": [{ "key": "Accept", "value": "application/json" }],
            "url": { "raw": "{{baseUrl}}/api/catalog/products/{{productSlug}}", "host": ["{{baseUrl}}"], "path": ["api", "catalog", "products", "{{productSlug}}"] }
          }
        }
      ]
    },
    {
      "name": "3. Buyer entitlement",
      "item": [
        {
          "name": "List purchases",
          "request": {
            "method": "GET",
            "header": [{ "key": "Accept", "value": "application/json" }],
            "url": { "raw": "{{baseUrl}}/api/orders/purchases", "host": ["{{baseUrl}}"], "path": ["api", "orders", "purchases"] }
          }
        },
        {
          "name": "Get deployment targets",
          "request": {
            "method": "GET",
            "header": [{ "key": "Accept", "value": "application/json" }],
            "url": { "raw": "{{baseUrl}}/api/install/products/{{productId}}/deploy-targets", "host": ["{{baseUrl}}"], "path": ["api", "install", "products", "{{productId}}", "deploy-targets"] }
          }
        },
        {
          "name": "Request short-lived download",
          "request": {
            "method": "GET",
            "header": [{ "key": "Accept", "value": "application/json" }],
            "url": { "raw": "{{baseUrl}}/api/install/products/{{productId}}/download", "host": ["{{baseUrl}}"], "path": ["api", "install", "products", "{{productId}}", "download"] },
            "description": "Returns an entitlement-checked URL that expires after five minutes. Request a fresh URL instead of caching it."
          }
        }
      ]
    },
    {
      "name": "4. Seller owner workflow",
      "item": [
        {
          "name": "List my seller products",
          "request": {
            "method": "GET",
            "header": [{ "key": "Accept", "value": "application/json" }],
            "url": { "raw": "{{baseUrl}}/api/seller/products", "host": ["{{baseUrl}}"], "path": ["api", "seller", "products"] },
            "description": "Stores the first product id and slug as collection variables when products are returned."
          },
          "event": [{ "listen": "test", "script": { "exec": ["pm.test('Owner product list is available', function () {", "  pm.response.to.have.status(200);", "  const products = pm.response.json().products || [];", "  if (products.length) {", "    pm.collectionVariables.set('productId', products[0].id);", "    if (products[0].slug) pm.collectionVariables.set('productSlug', products[0].slug);", "  }", "});"] } }]
        },
        {
          "name": "Get my product",
          "request": {
            "method": "GET",
            "header": [{ "key": "Accept", "value": "application/json" }],
            "url": { "raw": "{{baseUrl}}/api/seller/products/{{productId}}", "host": ["{{baseUrl}}"], "path": ["api", "seller", "products", "{{productId}}"] }
          }
        },
        {
          "name": "Check submission readiness",
          "request": {
            "method": "GET",
            "header": [{ "key": "Accept", "value": "application/json" }],
            "url": { "raw": "{{baseUrl}}/api/seller/products/{{productId}}/submission-readiness", "host": ["{{baseUrl}}"], "path": ["api", "seller", "products", "{{productId}}", "submission-readiness"] },
            "description": "Checks required listing metadata, immutable code and preview images. Missing file work returns a signed-in browser continuation URL; API/MCP tokens never upload bytes."
          },
          "event": [{ "listen": "test", "script": { "exec": ["pm.test('Readiness contract is actionable', function () {", "  pm.response.to.have.status(200);", "  const body = pm.response.json();", "  pm.expect(body.required).to.be.an('array');", "  pm.expect(body.missing).to.be.an('array');", "  pm.expect(body.browserActions.sellerManagerUrl).to.be.a('string');", "});"] } }]
        },
        {
          "name": "Get current prep quote",
          "request": {
            "method": "GET",
            "header": [{ "key": "Accept", "value": "application/json" }],
            "url": { "raw": "{{baseUrl}}/api/seller/products/{{productId}}/prep-quote", "host": ["{{baseUrl}}"], "path": ["api", "seller", "products", "{{productId}}", "prep-quote"] },
            "description": "Stores currentVersion and the selected tier's current points. Review both before enabling the run request."
          },
          "event": [{ "listen": "test", "script": { "exec": ["pm.test('Prep quote is version-bound', function () {", "  pm.response.to.have.status(200);", "  const quote = pm.response.json();", "  const tier = pm.collectionVariables.get('tier') || 'verified_listing';", "  pm.expect(quote.currentVersion).to.be.a('string');", "  pm.expect(quote.tiers[tier]).to.be.a('number');", "  pm.collectionVariables.set('expectedVersion', quote.currentVersion);", "  pm.collectionVariables.set('expectedPoints', String(quote.tiers[tier]));", "});"] } }]
        },
        {
          "name": "RUN PREP — SPENDS POINTS",
          "event": [{ "listen": "prerequest", "script": { "exec": ["if (pm.collectionVariables.get('allowPointSpend') !== 'RUN_SELLER_PREP') {", "  throw new Error('Blocked locally: set allowPointSpend=RUN_SELLER_PREP only after reviewing the current quote.');", "}", "if (!pm.collectionVariables.get('expectedVersion') || !pm.collectionVariables.get('expectedPoints')) {", "  throw new Error('Run Get current prep quote first.');", "}"] } }],
          "request": {
            "method": "POST",
            "header": [{ "key": "Content-Type", "value": "application/json" }],
            "body": { "mode": "raw", "raw": "{\n  \"tier\": \"{{tier}}\",\n  \"expectedVersion\": \"{{expectedVersion}}\",\n  \"expectedPoints\": {{expectedPoints}},\n  \"confirmation\": \"RUN_SELLER_PREP\"\n}" },
            "url": { "raw": "{{baseUrl}}/api/seller/products/{{productId}}/prep", "host": ["{{baseUrl}}"], "path": ["api", "seller", "products", "{{productId}}", "prep"] },
            "description": "This request spends Tetrees Points. The local guard, API confirmation, exact version, and exact cost must all match."
          }
        },
        {
          "name": "Read private seller report",
          "request": {
            "method": "GET",
            "header": [{ "key": "Accept", "value": "application/json" }],
            "url": { "raw": "{{baseUrl}}/api/seller/products/{{productId}}/report", "host": ["{{baseUrl}}"], "path": ["api", "seller", "products", "{{productId}}", "report"] },
            "description": "Returns normalized AVCP audition status, failed stages, owner-only evidence, fixes and next actions. Poll when verificationStatus is running."
          }
        },
        {
          "name": "Read Connect status",
          "request": {
            "method": "GET",
            "header": [{ "key": "Accept", "value": "application/json" }],
            "url": { "raw": "{{baseUrl}}/api/seller/connect/status", "host": ["{{baseUrl}}"], "path": ["api", "seller", "connect", "status"] }
          }
        }
      ]
    }
  ]
}
