{
  "info": {
    "name": "Cypress Integrations API",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
    "description": "Cypress Integrations API — both surfaces (/api/v1 modern + /api/compatible/v1 Manheim dialect).\n\nSetup: pick an environment (localhost/staging) and paste your org's API key\ninto the `apiKey` variable (minted on the Integrations page, or via\nscripts/seed-partner-integration.ts — shown once).\n\nRequests are numbered in flow order; create-requests capture ids\n(vehicleId, listingId, …) into environment vars for the follow-ups.\n\nFull walkthrough: docs/integrations/testing-runbook.md\n\nVariables: set `apiKey` (and `baseUrl` — default localhost:6200, staging https://staging.app.getcypress.ai) on the collection. Create-requests capture ids into collection variables for the follow-ups."
  },
  "variable": [
    {
      "key": "baseUrl",
      "value": "http://localhost:6200",
      "type": "string"
    },
    {
      "key": "apiKey",
      "value": "paste-your-key-here",
      "type": "string"
    },
    {
      "key": "vin",
      "value": "1FTFW1ET5DFC10312",
      "type": "string"
    }
  ],
  "item": [
    {
      "name": "organization",
      "item": [
        {
          "name": "GET /organization — what this key may do",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/organization",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "organization"
              ]
            },
            "description": "Start here. Answers any valid key, whatever the organization's status:\nproducts, channel grants, billing standing, and one entry per capability —\nallowed, or refused with the same reason code the refusing route returns."
          },
          "response": []
        }
      ]
    },
    {
      "name": "vehicles",
      "item": [
        {
          "name": "Create vehicle (draft-first)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "let body = {};",
                  "try { body = pm.response.json(); } catch (e) { /* empty response */ }",
                  "if (res.status === 201) pm.collectionVariables.set(\"vehicleId\", body.vehicle.id);"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/vehicles",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "vehicles"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"vin\": \"{{vin}}\",\n  \"modelYear\": 2013,\n  \"make\": \"Ford\",\n  \"model\": \"F-150\",\n  \"trim\": \"XLT\",\n  \"transmission\": \"AUTOMATIC\",\n  \"fuelType\": \"GASOLINE\",\n  \"exteriorColor\": \"White\",\n  \"interiorColor\": \"Gray\",\n  \"mileage\": 88500,\n  \"condition\": \"GOOD\",\n  \"stockNumber\": \"NU-1042\",\n  \"location\": { \"city\": \"Phoenix\", \"state\": \"AZ\", \"zip\": \"85001\" },\n  \"images\": [\n    { \"href\": \"https://images.example.com/nu-1042/front.jpg\", \"type\": \"PRIMARY_IMAGE\" }\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "201 + Location. The vehicle lands as DRAFT (draft-first). 409 if the VIN\nalready exists — use 02 to upsert instead, or delete first."
          },
          "response": []
        },
        {
          "name": "Upsert + embedded listing (straight to live)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "let body = {};",
                  "try { body = pm.response.json(); } catch (e) { /* empty response */ }",
                  "if (body.vehicle) pm.collectionVariables.set(\"vehicleId\", body.vehicle.id);",
                  "if (body.listing) pm.collectionVariables.set(\"listingId\", body.listing.id);"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/vehicles?mode=upsert",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "vehicles"
              ],
              "query": [
                {
                  "key": "mode",
                  "value": "upsert"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"vin\": \"{{vin}}\",\n  \"modelYear\": 2013,\n  \"make\": \"Ford\",\n  \"model\": \"F-150\",\n  \"trim\": \"XLT\",\n  \"mileage\": 88500,\n  \"listing\": {\n    \"floorPrice\": 18000,\n    \"buyNowPrice\": 22500,\n    \"startBidPrice\": 15000,\n    \"channels\": [\"MARKETPLACE\"],\n    \"listingMode\": \"IMMEDIATE\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "The single-request direct-to-market push: upserts by VIN, creates the\nlisting, and (listingMode IMMEDIATE) launches when the vehicle qualifies.\nResponse echoes the post-launch vehicle (status LISTED) + launched: true."
          },
          "response": []
        },
        {
          "name": "Get vehicle",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/vehicles/{{vehicleId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "vehicles",
                "{{vehicleId}}"
              ]
            },
            "description": "Every vehicle carries lifeStage (since API 1.1.0) next to status:\nstatus is where it is in the sale, lifeStage where it is in its life.\n\n{\n  \"vehicle\": {\n    \"id\": \"veh_…\", \"vin\": \"1FTFW1ET5DFC10312\",\n    \"status\": \"DRAFT\", \"lifeStage\": \"REMARKETING\",\n    \"pricing\": { \"buyNowPrice\": 22500, \"floorPrice\": 18000, \"startBidPrice\": null }\n  }\n}\n\n404 for an id from another organization — and for a vehicle the fleet\nkeeps in Operation or Planning, which the API does not show."
          },
          "response": []
        },
        {
          "name": "List vehicles (paginated)",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/vehicles?limit=25&offset=0",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "vehicles"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "25"
                },
                {
                  "key": "offset",
                  "value": "0"
                }
              ]
            },
            "description": "Sell stock only: lifeStage REMARKETING, POST_SALE or RETIRED. Vehicles\nthe fleet keeps in Operation or Planning are not listed (API 1.1.0), and\ntotalCount counts only what the list can return.\n\n?lifeStage=PLANNING,OPERATION (API 1.2.0) lists planning stock instead —\nfor a planning:read key on an organization with Planning. Otherwise it\nanswers 403 SCOPE_MISSING (key lacks planning:read) or\n403 PLANNING_NOT_ENABLED (organization has no Planning)."
          },
          "response": []
        },
        {
          "name": "Patch vehicle (partial)",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/vehicles/{{vehicleId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "vehicles",
                "{{vehicleId}}"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{ \"mileage\": 90000 }",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Only the provided keys change. Sending an images array replaces the\nAPI-owned photos (app uploads are never touched).\n\nlifeStage is read-only: echoing the value you read is ignored, a value\nacross the Planning/Sell line answers 409 LIFE_STAGE_READ_ONLY. A vehicle\nin Operation or Planning answers 409 PLANNING_STOCK:\n\n{ \"error\": \"This vehicle is in Planning, not in Sell. …\", \"code\": \"PLANNING_STOCK\" }"
          },
          "response": []
        },
        {
          "name": "Put vehicle (full re-push)",
          "request": {
            "method": "PUT",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/vehicles/{{vehicleId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "vehicles",
                "{{vehicleId}}"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"vin\": \"{{vin}}\",\n  \"modelYear\": 2013,\n  \"make\": \"Ford\",\n  \"model\": \"F-150\",\n  \"trim\": \"Lariat\",\n  \"mileage\": 90500\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Last write wins: mapper-owned fields absent from the payload are CLEARED\n(that is what makes \"re-push your whole list\" converge). VIN is immutable\n— a different VIN answers 409.\n\nA lifeStage copied from a read is accepted and ignored. Same\n409 PLANNING_STOCK / LIFE_STAGE_READ_ONLY rules as PATCH."
          },
          "response": []
        },
        {
          "name": "Bulk push (≤500)",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/vehicles/bulk?mode=upsert",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "vehicles",
                "bulk"
              ],
              "query": [
                {
                  "key": "mode",
                  "value": "upsert"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"vehicles\": [\n    { \"vin\": \"{{vin}}\", \"modelYear\": 2013, \"make\": \"Ford\", \"model\": \"F-150\" },\n    { \"vin\": \"1FAHP2E88DG100002\", \"modelYear\": 2013, \"make\": \"Ford\", \"model\": \"Fusion\",\n      \"listing\": { \"buyNowPrice\": 15500, \"listingMode\": \"REVIEW\" } },\n    { \"vin\": \"BADVIN\", \"modelYear\": 2013, \"make\": \"Ford\", \"model\": \"Focus\" }\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Items are independent — per-item {vin, status, href, errors}. The third\nrow 422s without failing the batch.\n\nA VIN the fleet keeps in Planning comes back as its own 409 item and the\nrest of the batch continues:\n\n{ \"vin\": \"…\", \"status\": 409, \"code\": \"PLANNING_STOCK\", \"errors\": [\"This vehicle is in Planning, not in Sell. …\"] }"
          },
          "response": []
        },
        {
          "name": "Report sold elsewhere (staged)",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/vehicles/{{vehicleId}}/disposition",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "vehicles",
                "{{vehicleId}}",
                "disposition"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{ \"type\": \"SOLD_ELSEWHERE\", \"salePrice\": 21000, \"saleDate\": \"2026-08-15\", \"reason\": \"Sold at local auction\" }",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Always 202: sold-elsewhere claims are staged for Cypress review (the\nplatform's standing rule). The decision arrives as\nVEHICLES.DISPOSITION.RESOLVED. Resolve it at /admin/update-requests."
          },
          "response": []
        },
        {
          "name": "Delete vehicle (unlisted only)",
          "request": {
            "method": "DELETE",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/vehicles/{{vehicleId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "vehicles",
                "{{vehicleId}}"
              ]
            },
            "description": "204 for DRAFT/REVIEW/PENDING_APPROVAL/APPROVED. A listed vehicle answers\n409 — cancel its listing first (2-listings / 06)."
          },
          "response": []
        }
      ]
    },
    {
      "name": "listings",
      "item": [
        {
          "name": "Create listing (draft-first)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "let body = {};",
                  "try { body = pm.response.json(); } catch (e) { /* empty response */ }",
                  "if (res.status === 201) pm.collectionVariables.set(\"listingId\", body.listing.id);"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/listings",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "listings"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"vehicleId\": \"{{vehicleId}}\",\n  \"floorPrice\": 18000,\n  \"buyNowPrice\": 22500,\n  \"startBidPrice\": 15000,\n  \"channels\": [\"MARKETPLACE\"],\n  \"listingMode\": \"REVIEW\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Records intent (REQUESTED) + applies pricing: buyNow→asking, floor→floor,\nstartBid→auto-decline threshold. listingMode IMMEDIATE launches in-request.\nChannels are validated against your org's grants (DIRECT_LINK needs the\nP2P channel enabled). One open listing per vehicle → 409."
          },
          "response": []
        },
        {
          "name": "Get listing",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/listings/{{listingId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "listings",
                "{{listingId}}"
              ]
            }
          },
          "response": []
        },
        {
          "name": "Update pricing",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/listings/{{listingId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "listings",
                "{{listingId}}"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{ \"buyNowPrice\": 21900, \"floorPrice\": 17500 }",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Applies immediately to the vehicle and, when live, to the published\nmarketplace listing's asking price.\n\nSince 1.5.0, the app's price rules: 409 CONFLICT while the vehicle is\nUnder Offer, Offer Accepted, in Due Diligence, Ready to Deliver or Sold\n(a deal was agreed against its price); 403 BELOW_FLOOR when the buy-now\nwould sit below the floor; 422 INVALID for a buy-now with no floor.\nNothing is written when it is refused. ?dryRun=true checks without\nwriting; an Idempotency-Key makes a retry safe."
          },
          "response": []
        },
        {
          "name": "Pause (temporarily off market)",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/listings/{{listingId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "listings",
                "{{listingId}}"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{ \"status\": \"PAUSED\" }",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Vehicle → ON_HOLD, listing → PAUSED. 409 while a deal is in progress —\na negotiation cannot be paused."
          },
          "response": []
        },
        {
          "name": "Resume",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/listings/{{listingId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "listings",
                "{{listingId}}"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{ \"status\": \"ACTIVE\" }",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        },
        {
          "name": "Cancel listing (delists live vehicles)",
          "request": {
            "method": "DELETE",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/listings/{{listingId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "listings",
                "{{listingId}}"
              ]
            },
            "description": "204: cancelled — a live vehicle is delisted (archived with full cleanup;\nCypress can restore it). 202: the vehicle is mid-deal, so the cancel was\nSTAGED for Cypress resolution instead of applied."
          },
          "response": []
        },
        {
          "name": "Bulk update by VINs",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/listings/bulk",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "listings",
                "bulk"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"vins\": [\"{{vin}}\", \"1FAHP2E88DG100002\"],\n  \"set\": { \"buyNowPrice\": 20900 }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Targets open listings by VIN (or pass listingIds). ≤500, per-item results;\na conflict on one row never fails the batch.\n\nSince 1.5.0 each item runs the same price rules as 03: an item refused\ncarries its status and code (409 CONFLICT, 403 BELOW_FLOOR, 422 INVALID)\nand the rest of the batch goes ahead."
          },
          "response": []
        },
        {
          "name": "List listings (?status=)",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/listings?limit=25&status=ACTIVE",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "listings"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "25"
                },
                {
                  "key": "status",
                  "value": "ACTIVE"
                }
              ]
            }
          },
          "response": []
        },
        {
          "name": "POST /listings/bulk — upsert by your own ids",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/listings/bulk",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "listings",
                "bulk"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"items\": [\n    { \"vehicleId\": \"{{vehicleId}}\", \"floorPrice\": 17500, \"buyNowPrice\": 21900, \"externalIds\": [{ \"source\": \"my-dms\", \"id\": \"L-1001\" }] }\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Since 1.5.0. Up to 100 rows, each a POST /listings body, matched by its\nexternalIds: a row whose ids name one of your listings changes its prices\nand channels (the price rules of 03 apply: 409 CONFLICT under a live offer\nor sale, 403 BELOW_FLOOR for a buy-now below the floor); one that names none\nis listed on its vehicleId. Per-row results; ?dryRun=true and an\nIdempotency-Key as every bulk upsert. Run it twice: the second run answers\n200 (changed), not a second listing."
          },
          "response": []
        }
      ]
    },
    {
      "name": "webhooks",
      "item": [
        {
          "name": "Register webhook subscription",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "let body = {};",
                  "try { body = pm.response.json(); } catch (e) { /* empty response */ }",
                  "if (res.status === 201) {",
                  "  pm.collectionVariables.set(\"subscriptionId\", body.subscription.id);",
                  "  pm.collectionVariables.set(\"signingSecret\", body.signingSecret);",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/webhooks/subscriptions",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "webhooks",
                "subscriptions"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"callback\": \"https://your-endpoint.example/webhooks/cypress\",\n  \"headers\": { \"x-api-key\": \"the-secret-your-endpoint-expects\" },\n  \"emails\": [\"ops@your-company.example\"],\n  \"eventTypes\": [],\n  \"dialect\": \"CYPRESS\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "callback must be HTTPS (localhost testing: seed an http subscriber with\nscripts/seed-partner-integration.ts or the mock receiver runbook).\nsigningSecret is returned ONCE — verify x-cypress-signature with it.\neventTypes [] = all events except the opt-in ones (PLAN.*, BUY.* and\nVEHICLES.* about planning stock; list them to receive them); dialect MANHEIM\nswitches vocabulary to UNITS./OFFERINGS. names (the opt-in ones need CYPRESS)."
          },
          "response": []
        },
        {
          "name": "List subscriptions",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/webhooks/subscriptions",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "webhooks",
                "subscriptions"
              ]
            },
            "description": "Header VALUES are masked — they never leave the database after save."
          },
          "response": []
        },
        {
          "name": "Send PING.TEST",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/webhooks/subscriptions/{{subscriptionId}}/test",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "webhooks",
                "subscriptions",
                "{{subscriptionId}}",
                "test"
              ]
            },
            "description": "202 — a PING.TEST goes through the REAL pipeline (signature, headers,\nretries). Watch it in 05-deliveries."
          },
          "response": []
        },
        {
          "name": "Update subscription",
          "request": {
            "method": "PUT",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/webhooks/subscriptions/{{subscriptionId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "webhooks",
                "subscriptions",
                "{{subscriptionId}}"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"callback\": \"https://your-endpoint.example/webhooks/cypress\",\n  \"headers\": { \"x-api-key\": \"rotated-endpoint-secret\" },\n  \"emails\": [\"ops@your-company.example\"],\n  \"eventTypes\": [\"LISTINGS.PURCHASED\", \"CLOSING.DOCUMENT.SIGNED\"],\n  \"dialect\": \"CYPRESS\",\n  \"inactive\": false\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Full replace (partner surface). Filtering to just the sale-critical events\nhere; [] = everything."
          },
          "response": []
        },
        {
          "name": "Delivery log",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/deliveries?limit=25",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "deliveries"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "25"
                }
              ]
            },
            "description": "Add &status=DEAD or &eventType=LISTINGS.PURCHASED to filter. GET a single\ndelivery (…/deliveries/{id}) for the envelope as sent + your endpoint's\nrecorded response."
          },
          "response": []
        },
        {
          "name": "Delete subscription",
          "request": {
            "method": "DELETE",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/webhooks/subscriptions/{{subscriptionId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "webhooks",
                "subscriptions",
                "{{subscriptionId}}"
              ]
            }
          },
          "response": []
        }
      ]
    },
    {
      "name": "manheim compatible",
      "item": [
        {
          "name": "POST /units (Manheim payload)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "let body = {};",
                  "try { body = pm.response.json(); } catch (e) { /* empty response */ }",
                  "if (res.status === 201) {",
                  "  pm.collectionVariables.set(\"unitId\", body.href.split(\"/\").pop());",
                  "  if (body.offering) pm.collectionVariables.set(\"offeringId\", body.offering.href.split(\"/\").pop());",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/compatible/v1/units",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "compatible",
                "v1",
                "units"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"type\": \"PASSENGER_VEHICLE\",\n  \"vin\": \"{{vin}}\",\n  \"description\": {\n    \"modelYear\": 2013,\n    \"make\": \"Ford\",\n    \"model\": \"F-150\",\n    \"trim\": \"XLT\",\n    \"transmission\": \"AUTOMATIC\",\n    \"engine\": { \"type\": \"V6\", \"fuel\": \"GASOLINE\" },\n    \"exteriorColor\": \"White\",\n    \"interiorColor\": \"Gray\",\n    \"driveType\": \"4_WHEEL_DRIVE\",\n    \"doorCount\": 4\n  },\n  \"odometer\": { \"reading\": 88500, \"units\": \"MILES\" },\n  \"physicalLocation\": { \"city\": \"Phoenix\", \"state\": \"AZ\", \"zip\": \"85001\" },\n  \"images\": [\n    { \"type\": \"PRIMARY_IMAGE\", \"href\": \"https://images.example.com/nu-1042/front.jpg\" }\n  ],\n  \"offering\": {\n    \"buyNowPrice\": 22500,\n    \"floorPrice\": 18000,\n    \"listingMode\": \"IMMEDIATE\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Manheim conventions: 201 + Location header, 409 on duplicate VIN.\nKILOMETERS odometers convert to miles. The `offering` block is the Cypress\nextension for single-request direct-to-market. Unmapped fields (doorCount,\nengine.type…) are preserved and echoed back on GET."
          },
          "response": []
        },
        {
          "name": "GET /units/id/{id}",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/compatible/v1/units/id/{{unitId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "compatible",
                "v1",
                "units",
                "id",
                "{{unitId}}"
              ]
            },
            "description": "Manheim unit shape plus Cypress extensions: pricing, condition and\nlifeStage (API 1.1.0). Units the fleet keeps in Operation or Planning\nanswer 404 here; writes to them answer 409 PLANNING_STOCK."
          },
          "response": []
        },
        {
          "name": "POST /units/id/{id} (update-is-POST → 204)",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/compatible/v1/units/id/{{unitId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "compatible",
                "v1",
                "units",
                "id",
                "{{unitId}}"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"vin\": \"{{vin}}\",\n  \"description\": {\n    \"modelYear\": 2013,\n    \"make\": \"Ford\",\n    \"model\": \"F-150\",\n    \"trim\": \"Lariat\"\n  },\n  \"odometer\": { \"reading\": 91000, \"units\": \"MILES\" }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Full re-push, Manheim style: POST to the resource → 204 empty body.\nAbsent mapped fields clear; VIN is immutable (409)."
          },
          "response": []
        },
        {
          "name": "GET /units/mine",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/compatible/v1/units/mine?limit=25&offset=0",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "compatible",
                "v1",
                "units",
                "mine"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "25"
                },
                {
                  "key": "offset",
                  "value": "0"
                }
              ]
            }
          },
          "response": []
        },
        {
          "name": "POST /units/bulk (≤100)",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/compatible/v1/units/bulk",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "compatible",
                "v1",
                "units",
                "bulk"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"units\": [\n    { \"vin\": \"1FAHP2E88DG100002\", \"description\": { \"modelYear\": 2013, \"make\": \"Ford\", \"model\": \"Fusion\" } },\n    { \"vin\": \"{{vin}}\", \"description\": { \"modelYear\": 2013, \"make\": \"Ford\", \"model\": \"F-150\" } }\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        },
        {
          "name": "POST /offerings (unit.href reference)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "let body = {};",
                  "try { body = pm.response.json(); } catch (e) { /* empty response */ }",
                  "if (res.status === 201) pm.collectionVariables.set(\"offeringId\", body.offering.href.split(\"/\").pop());"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/compatible/v1/offerings",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "compatible",
                "v1",
                "offerings"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"unit\": { \"href\": \"{{baseUrl}}/api/compatible/v1/units/id/{{unitId}}\" },\n  \"floorPrice\": 18000,\n  \"buyNowPrice\": 22500,\n  \"startBidPrice\": 15000\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Accepts Manheim-style unit.href, or unitId/unitHref. 409 when an open\noffering exists."
          },
          "response": []
        },
        {
          "name": "GET /offerings/id/{id}",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/compatible/v1/offerings/id/{{offeringId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "compatible",
                "v1",
                "offerings",
                "id",
                "{{offeringId}}"
              ]
            }
          },
          "response": []
        },
        {
          "name": "POST /offerings/id/{id} (reprice → 204)",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/compatible/v1/offerings/id/{{offeringId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "compatible",
                "v1",
                "offerings",
                "id",
                "{{offeringId}}"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{ \"buyNowPrice\": 21900 }",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Manheim's update-is-POST: 204 with an empty body. Since 1.5.0 the same price\nrules as the Cypress surface's PATCH: 409 CONFLICT while the vehicle is\nunder offer or sold, 403 BELOW_FLOOR for a buy-now below the floor, 422\nINVALID for a buy-now with no floor. Nothing is written when it is refused."
          },
          "response": []
        },
        {
          "name": "POST /offerings/…/actions/pause",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/compatible/v1/offerings/id/{{offeringId}}/actions/pause",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "compatible",
                "v1",
                "offerings",
                "id",
                "{{offeringId}}",
                "actions",
                "pause"
              ]
            },
            "description": "Manheim's action-URL idiom (this surface only) → 204."
          },
          "response": []
        },
        {
          "name": "POST /offerings/…/actions/resume",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/compatible/v1/offerings/id/{{offeringId}}/actions/resume",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "compatible",
                "v1",
                "offerings",
                "id",
                "{{offeringId}}",
                "actions",
                "resume"
              ]
            }
          },
          "response": []
        },
        {
          "name": "DELETE /offerings/id/{id}",
          "request": {
            "method": "DELETE",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/compatible/v1/offerings/id/{{offeringId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "compatible",
                "v1",
                "offerings",
                "id",
                "{{offeringId}}"
              ]
            },
            "description": "204 cancelled (live units delisted); 202 when mid-deal → staged for\nCypress resolution."
          },
          "response": []
        },
        {
          "name": "POST /units/…/actions/sold_elsewhere",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/compatible/v1/units/id/{{unitId}}/actions/sold_elsewhere",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "compatible",
                "v1",
                "units",
                "id",
                "{{unitId}}",
                "actions",
                "sold_elsewhere"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{ \"salePrice\": 21000, \"saleDate\": \"2026-08-15\" }",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        },
        {
          "name": "POST /subscribers (Manheim mirror)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "let body = {};",
                  "try { body = pm.response.json(); } catch (e) { /* empty response */ }",
                  "if (res.status === 201) {",
                  "  pm.collectionVariables.set(\"subscriberId\", body.subscriber.id);",
                  "  pm.collectionVariables.set(\"signingSecret\", body.signingSecret);",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/compatible/v1/subscribers",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "compatible",
                "v1",
                "subscribers"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"callback\": \"https://your-endpoint.example/cypress\",\n  \"headers\": { \"x-api-key\": \"the-secret-your-endpoint-expects\" },\n  \"emails\": [\"ops@your-company.example\"],\n  \"eventTypes\": [\"OFFERINGS.PURCHASED\", \"UNITS.CREATED\"]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Manheim's {callback, headers, emails} shape. Defaults to the MANHEIM\ndialect (envelopes speak UNITS./OFFERINGS.), and accepts eventTypes in\neither vocabulary — stored canonically."
          },
          "response": []
        },
        {
          "name": "POST /subscribers/…/test",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/compatible/v1/subscribers/id/{{subscriberId}}/test",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "compatible",
                "v1",
                "subscribers",
                "id",
                "{{subscriberId}}",
                "test"
              ]
            }
          },
          "response": []
        },
        {
          "name": "DELETE /units/id/{id}",
          "request": {
            "method": "DELETE",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/compatible/v1/units/id/{{unitId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "compatible",
                "v1",
                "units",
                "id",
                "{{unitId}}"
              ]
            }
          },
          "response": []
        }
      ]
    },
    {
      "name": "planning",
      "item": [
        {
          "name": "Push a vehicle in service (lifeStage OPERATION)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "let body = {};",
                  "try { body = pm.response.json(); } catch (e) { /* empty response */ }",
                  "if (body.vehicle) pm.collectionVariables.set(\"operationVehicleId\", body.vehicle.id);",
                  "pm.collectionVariables.set(\"today\", new Date().toISOString().slice(0, 10));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/vehicles?mode=upsert",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "vehicles"
              ],
              "query": [
                {
                  "key": "mode",
                  "value": "upsert"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"vin\": \"1FTBR1C80MKA40011\",\n  \"modelYear\": 2021,\n  \"make\": \"Ford\",\n  \"model\": \"Transit\",\n  \"trim\": \"T-250\",\n  \"mileage\": 38400,\n  \"condition\": 3.5,\n  \"stockNumber\": \"NU-T250-011\",\n  \"location\": { \"city\": \"Orlando\", \"state\": \"FL\", \"zip\": \"32801\" },\n  \"lifeStage\": \"OPERATION\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Needs the vehicles + planning:write scopes and Planning switched on for\nthe organization (403 SCOPE_MISSING / PLANNING_NOT_ENABLED otherwise).\n\n201 (200 on a re-run — ?mode=upsert). The vehicle lands as planning stock\nin service: lifeStage OPERATION, in the plan, never in the Sell intake.\nThe mileage is recorded as an odometer reading. No valuation is bought —\nthe daily valuation sweep values new planning stock (up to 250 a run).\nAn OPERATION push sends no PLAN.VEHICLE.ENTERED (it is not under\nconsideration).\n\nRequests 10–12 use this vehicle (odometer, cost, departure); this request\nalso captures today's UTC date into \"today\" for 10's readAt."
          },
          "response": []
        },
        {
          "name": "Push a vehicle onto the bench (lifeStage PLANNING) with ownership",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "let body = {};",
                  "try { body = pm.response.json(); } catch (e) { /* empty response */ }",
                  "if (body.vehicle) pm.collectionVariables.set(\"planningVehicleId\", body.vehicle.id);"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/vehicles?mode=upsert",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "vehicles"
              ],
              "query": [
                {
                  "key": "mode",
                  "value": "upsert"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"vin\": \"1FTBR1C82MKA40012\",\n  \"modelYear\": 2021,\n  \"make\": \"Ford\",\n  \"model\": \"Transit\",\n  \"trim\": \"T-250\",\n  \"mileage\": 52100,\n  \"condition\": 3.0,\n  \"stockNumber\": \"NU-T250-012\",\n  \"location\": { \"city\": \"Orlando\", \"state\": \"FL\", \"zip\": \"32801\" },\n  \"lifeStage\": \"PLANNING\",\n  \"ownership\": {\n    \"purchasePrice\": 38900,\n    \"purchaseDate\": \"2021-03-15\",\n    \"acquisitionMethod\": \"FINANCING\",\n    \"downPayment\": 7900,\n    \"loanAmount\": 31000,\n    \"loanTermMonths\": 60,\n    \"interestRate\": 6.9\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Benched as a candidate: lifeStage PLANNING. Every PLANNING item of one\nrequest (single or bulk) is benched in ONE plan version, and each sends\nPLAN.VEHICLE.ENTERED to subscriptions that opted in.\n\nThe ownership block is checked BEFORE anything is created — a payoff\nbefore the purchase date, or a balloon as large as the loan, answers 422\nwith details.errors and creates nothing. Softer findings come back in\n\"warnings\" and are saved.\n\nIf the bench step doesn't land (a busy plan, no plan) the push still\nanswers 201 (200 on an upsert) with the vehicle in OPERATION,\n\"planningStep\": { \"error\": … } and \"code\" PLAN_BUSY (plus Retry-After)\nor NO_PLAN — bench it with 05-style\nPOST /planning/moves { \"to\": \"BENCH\" } or re-run this request.\n\nRe-running after 09 (the hand-off) answers 409 LIFE_STAGE_READ_ONLY: the\nvehicle is in Sell now, and a push never moves it back."
          },
          "response": []
        },
        {
          "name": "GET /planning/plan — windows and tracks",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "let body = {};",
                  "try { body = pm.response.json(); } catch (e) { /* empty response */ }",
                  "const open = (body.windows || []).filter((w) => w.closed !== true && w.state !== 'CLOSED');",
                  "if (open.length) pm.collectionVariables.set(\"windowId\", open[open.length - 1].id);"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/planning/plan",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "planning",
                "plan"
              ]
            },
            "description": "Needs planning:read. The strategy, the plan's version, the six sale\nwindows and the tracks. Captures the LAST open window's id into windowId\nfor 05 and 08.\n\n\"Open\" means closed is not true (API 1.4.0) and the window's own state is\nnot CLOSED. Each window carries \"quarter\" (2026-Q4) and \"closed\": true once\nits quarter is over. Do not test \"state\" alone: a window of a closed\nquarter that has not been swept yet still reads PLANNED or ACTIVE, and a\nwrite to it answers 409 QUARTER_CLOSED.\n\nWindow ids change with every plan version — use \"id\" for writes, and\nfollow a window across versions by its \"lineage\" (2026W44-2026W45).\nTracks are named by \"key\" (POST /planning/moves/track)."
          },
          "response": []
        },
        {
          "name": "GET /planning/vehicles — the plan's vehicles",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/planning/vehicles?limit=25&offset=0&lifeStage=OPERATION,PLANNING",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "planning",
                "vehicles"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "25"
                },
                {
                  "key": "offset",
                  "value": "0"
                },
                {
                  "key": "lifeStage",
                  "value": "OPERATION,PLANNING"
                }
              ]
            },
            "description": "Needs planning:read. One row per vehicle in the latest plan, by rank:\nmembershipState, window { id, lineage, label }, track (the effective\ntrack — the default for a vehicle not on one), plannedValue, open\nblockers, market { value, band, asOf } from the latest valuation (null\nuntil valued) and the stored plan advice.\n\nFilters: windowId, windowLineage, state, trackKey, lifeStage.\n\nThe expected realized value, trend and verdict are on\nGET /api/v1/planning/vehicles/{id} only (up to 60 s stale)."
          },
          "response": []
        },
        {
          "name": "Move the benched vehicle into a sale window",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/planning/moves",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "planning",
                "moves"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"vehicleIds\": [\"{{planningVehicleId}}\"],\n  \"to\": { \"windowId\": \"{{windowId}}\" },\n  \"reason\": \"Lease return due in this window\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Needs planning:write. One target per call ({ windowId }, \"BENCH\" or\n\"OPERATION\"), up to 50 vehicles — one call is ONE plan version.\n\n200 { planVersion, moved, skipped, findings }. A vehicle that cannot go\nis listed in \"skipped\" with its reason (an unknown or another\norganization's id: \"not in the plan\") and the rest move.\n\n409 PLAN_BUSY + Retry-After: 2 — another write took the version; retry.\n404 WINDOW_GONE — re-run 03 (window ids change with every version).\n409 QUARTER_CLOSED — that window's quarter is over (03 says \"closed\":\ntrue). Nothing was written and it is not retryable: pick a window with\n\"closed\": false. details.vehicleIds names the vehicles it blocks.\n409 WINDOW_CLOSED — the window itself has closed, in a quarter still in\nprogress: pick an open window."
          },
          "response": []
        },
        {
          "name": "Add a PAYOFF blocker",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "let body = {};",
                  "try { body = pm.response.json(); } catch (e) { /* empty response */ }",
                  "if (body.id) pm.collectionVariables.set(\"blockerId\", body.id);"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/planning/blockers",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "planning",
                "blockers"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"vehicleId\": \"{{planningVehicleId}}\",\n  \"kind\": \"PAYOFF\",\n  \"note\": \"Lien release pending from the lender\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Needs planning:write. 201 { id, planVersion }. A blocker gates the sale,\nnot the planning: at the hand-off (08/09) this vehicle would be held\n(HOLD_CONDITIONAL / HELD_BLOCKER_OPEN) until it is resolved. An EVIDENCE\nblocker stops a vehicle being scheduled at all.\n\nRead a vehicle's blockers: GET /api/v1/planning/blockers?vehicleId=…"
          },
          "response": []
        },
        {
          "name": "Resolve the blocker (resolvingRef)",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/planning/blockers/{{blockerId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "planning",
                "blockers",
                "{{blockerId}}"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{ \"resolvingRef\": \"Lien release LR-20431 received\" }",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Needs planning:write. resolvingRef (5+ characters) is the evidence that\ncleared it. 200 { resolved: true, planVersion }; a waiting (CONDITIONAL)\nvehicle whose last blocker this was returns to STAGED in the same\nversion. Send { \"kind\" } and/or { \"note\" } instead to edit an open one.\n409 RESOLVED — already resolved. Deleting a blocker is not on the API."
          },
          "response": []
        },
        {
          "name": "Preview the window's cohort (digest, 24 h)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "let body = {};",
                  "try { body = pm.response.json(); } catch (e) { /* empty response */ }",
                  "if (body.digest) {",
                  "  pm.collectionVariables.set(\"windowId\", body.windowId);",
                  "  pm.collectionVariables.set(\"cohortDigest\", body.digest);",
                  "  pm.collectionVariables.set(\"cohortExpiresAt\", body.expiresAt);",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/planning/windows/{{windowId}}/cohort-preview",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "planning",
                "windows",
                "{{windowId}}",
                "cohort-preview"
              ]
            },
            "description": "Needs planning:write. Writes nothing. The window's STAGED and CONDITIONAL\nvehicles, each with a disposition — PROMOTE, HOLD_CONDITIONAL (an open\nblocker) or BLOCKED (an open EVIDENCE blocker) — plus the digest that\nbinds a confirm to exactly this cohort, and expiresAt (24 hours).\n\nCaptures the CURRENT window id, the digest and expiresAt for 09.\n\n409 QUARTER_CLOSED — the window's quarter is over, so there is no cohort to\nconfirm (details.quarter names it). 409 WINDOW_CLOSED — the window itself\nhas closed, in a quarter still in progress."
          },
          "response": []
        },
        {
          "name": "Confirm the cohort — hand it to Sell",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/planning/windows/{{windowId}}/cohort-confirm",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "planning",
                "windows",
                "{{windowId}}",
                "cohort-confirm"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"digest\": \"{{cohortDigest}}\",\n  \"expiresAt\": \"{{cohortExpiresAt}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Needs planning:write. Echo both digest and expiresAt from 08.\n\n200 { planVersion, results: [{ vehicleId, result }] } — INTAKE_CONFIRMED\n(in the Sell intake: lifeStage REMARKETING, status still DRAFT, nothing\nlisted; it now shows in GET /api/v1/vehicles), HELD_BLOCKER_OPEN or\nBLOCKED_EVIDENCE. Sends PLAN.HANDED_TO_SELL to opted-in subscriptions.\n\n409 PREVIEW_STALE — the preview expired or the cohort changed: re-run 08.\n409 QUARTER_CLOSED — the window's quarter is over: nothing was written\nand it is not retryable (details.quarter names the quarter). Use a window\nof a quarter in progress (\"closed\": false in 03).\n409 WINDOW_CLOSED — the window itself has closed, in a quarter still in\nprogress. 409 PLAN_BUSY + Retry-After: retry.\nReturn a vehicle to the bench: POST /api/v1/planning/demotions\n{ \"vehicleId\": … } — before it is listed (409 SELLING_BEGUN after)."
          },
          "response": []
        },
        {
          "name": "Record an odometer reading",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/vehicles/{{operationVehicleId}}/odometer-readings",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "vehicles",
                "{{operationVehicleId}}",
                "odometer-readings"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{ \"readAt\": \"{{today}}\", \"miles\": 39850 }",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Planning stock only (a vehicle in Sell answers 409 IN_SELL — send its\nmileage with PATCH). Needs vehicles + planning:write. Exactly one of\nmiles or km (converted). readAt is YYYY-MM-DD, not in the future.\n\n201 { reading, mileage }. A reading dated on or after the latest becomes\nthe vehicle's mileage; a back-dated one is history only. A reading that\nruns the series backwards answers 409 ODOMETER_ROLLBACK with\ndetails.recorded — send \"force\": true for a replaced odometer.\nGET lists readings newest first (up to 100).\n\nreadAt is today's UTC date, captured by 01 — 01's push recorded 38,400 mi\ndated today, so this reading is the newest and becomes the mileage."
          },
          "response": []
        },
        {
          "name": "Record a cost event (idempotent with externalRef)",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/vehicles/{{operationVehicleId}}/cost-events",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "vehicles",
                "{{operationVehicleId}}",
                "cost-events"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"category\": \"REPAIR\",\n  \"amount\": 1240.5,\n  \"eventDate\": \"2026-09-12\",\n  \"note\": \"Rear brake pads and rotors\",\n  \"externalRef\": \"WO-88412\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Any vehicle of the organization, Sell stock included. Needs vehicles +\nplanning:write. Categories: MAINTENANCE, REPAIR, FUEL, INSURANCE,\nREGISTRATION, OTHER.\n\n201 { costEvent } the first time; re-run it: 200 with the STORED row —\nan externalRef already stored for the vehicle never writes a second\ncost, even if the body differs.\n\nThe plan's carry cost does not read cost events yet (it uses the cost\nassumptions set in the app). GET lists them newest first (up to 100)."
          },
          "response": []
        },
        {
          "name": "Report a departure (staged for Cypress review)",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/vehicles/{{operationVehicleId}}/departure",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "vehicles",
                "{{operationVehicleId}}",
                "departure"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"kind\": \"SOLD_OFF_PLATFORM\",\n  \"reason\": \"Sold to the lessee at end of term\",\n  \"soldPrice\": 18500,\n  \"soldAt\": \"2026-09-28\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Planning stock only (a vehicle in Sell answers 409 IN_SELL — use\n/vehicles/{id}/disposition). Needs vehicles + planning:write.\n\n202 { staged, requestId, alreadyPending } — never applied directly: a\nCypress Manager reviews it. VEHICLES.DISPOSITION.STAGED now,\nVEHICLES.DISPOSITION.RESOLVED with the decision. kind LEFT_FLEET takes\nno soldPrice/soldAt (422). A second departure while one is pending\nanswers 202 with alreadyPending: true."
          },
          "response": []
        }
      ]
    },
    {
      "name": "buy planning",
      "item": [
        {
          "name": "GET /organization — can this key plan purchases?",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/organization",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "organization"
              ]
            },
            "description": "Start here. Needs no scope. Look for products.buyPlanning.enabled: true and\nthe capabilities buy-planning.read / buy-planning.write with \"allowed\": true.\n\nBuy planning is a product switch of its own (separate from Planning). A key\nmade on the Integrations page needs \"Buy planning (read and write)\" for this\nwhole folder; \"Buy planning (read)\" reaches 02, 05 and 07 only.\n\nallowed: false carries the reason the refusing route would return:\nBUY_PLANNING_NOT_ENABLED (ask Cypress to turn Buy planning on) or\nSCOPE_MISSING (ask your admin to add the scope; no need to rotate the key)."
          },
          "response": []
        },
        {
          "name": "GET /buy-planning/quarters/current — the quarter",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "let body = {};",
                  "try { body = pm.response.json(); } catch (e) { /* empty response */ }",
                  "if (body.periodKey) {",
                  "  pm.collectionVariables.set(\"buyPeriodKey\", body.periodKey);",
                  "  pm.collectionVariables.set(\"buyDigest\", body.digest);",
                  "  // A needed-by date in the middle of the quarter, and today (UTC) for the purchase in 06.",
                  "  const mid = new Date(body.start + \"T00:00:00Z\");",
                  "  mid.setUTCDate(mid.getUTCDate() + 45);",
                  "  pm.collectionVariables.set(\"buyNeedBy\", mid.toISOString().slice(0, 10));",
                  "  pm.collectionVariables.set(\"buyToday\", new Date().toISOString().slice(0, 10));",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/buy-planning/quarters/current",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "buy-planning",
                "quarters",
                "current"
              ]
            },
            "description": "Needs buy-planning:read. \"current\" is the quarter in progress; a key like\n2026-Q4 works too. A quarter nobody has set yet is an empty one (no goal, no\nbudget, \"approval\": null), never a 404.\n\n200 { periodKey, label, start, end, closed, unitsGoal, budget, mandate,\napproval, progress: { bought, inClosing, spent, inClosingAmount }, digest }.\n\"progress\" counts the purchases made in the quarter by the app's own rule.\n\"digest\" is what an approval binds to (08).\n\nCaptures the quarter's key and digest, a needed-by date in the middle of\nthe quarter (buyNeedBy, for 04) and today (buyToday, for 06).\n\n403 BUY_PLANNING_NOT_ENABLED / SCOPE_MISSING — see 01."
          },
          "response": []
        },
        {
          "name": "PUT /buy-planning/quarters/{periodKey} — goal, budget, mandate",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "let body = {};",
                  "try { body = pm.response.json(); } catch (e) { /* empty response */ }",
                  "if (body.digest) pm.collectionVariables.set(\"buyDigest\", body.digest);"
                ]
              }
            }
          ],
          "request": {
            "method": "PUT",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/buy-planning/quarters/{{buyPeriodKey}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "buy-planning",
                "quarters",
                "{{buyPeriodKey}}"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"unitsGoal\": 40,\n  \"budget\": 900000,\n  \"mandate\": \"USUAL_MIX\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Needs buy-planning:write. Send unitsGoal and budget every time (null clears\none); leave mandate out to keep the quarter's mandate (null clears it). A\nforgotten goal or budget is a 422, never a silently cleared one. There is no\nnote: the dealer's note on the quarter is never touched.\n\n200 the quarter again, with the new digest (captured for 08).\n\n409 QUARTER_CLOSED — the quarter's last day has passed, so its goal no\nlonger changes (a closed quarter's goal is what Review compares it\nagainst). Nothing was written and it is not retryable."
          },
          "response": []
        },
        {
          "name": "POST /buy-planning/targets — add a target",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "let body = {};",
                  "try { body = pm.response.json(); } catch (e) { /* empty response */ }",
                  "if (body.id) pm.collectionVariables.set(\"buyTargetId\", body.id);"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/buy-planning/targets",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "buy-planning",
                "targets"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"make\": \"Toyota\",\n  \"model\": \"RAV4\",\n  \"trims\": [\"XLE\"],\n  \"yearMin\": 2021,\n  \"yearMax\": 2023,\n  \"mileageMax\": 60000,\n  \"states\": [\"FL\", \"GA\"],\n  \"quantity\": 6,\n  \"needBy\": \"{{buyNeedBy}}\",\n  \"targetUnitPrice\": 25000,\n  \"maxUnitPrice\": 27000,\n  \"priority\": 1,\n  \"track\": \"BALANCED\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Needs buy-planning:write. A vehicle you want (one make and model, or a\nvehicle class), how many, and the week you need them by. The needBy snaps to\nthe week's Sunday (\"needByWeek\": \"W48\"); the target counts in the quarter of\nthat week's Thursday (\"periodKey\"). A target that names no track takes the\nplan's default track.\n\n201 the target: status, displayStatus (what a person reads: OPEN, FILLED,\nPAUSED, CLOSED or ENDED), bought, inClosing, remaining. Captures its id for\n05 and 06.\n\n409 QUARTER_CLOSED — the target is needed in a quarter that is over; nothing\nwas written, not retryable. 422 — the app's own checks (a real date, years\nand mileage in order, a target price at or below the maximum).\n\nPATCH /targets/{id} takes { \"status\": \"PAUSED\" } alone, or the whole body to\nedit; DELETE removes a target that has no purchases (409 HAS_PURCHASES\notherwise: close it)."
          },
          "response": []
        },
        {
          "name": "GET /buy-planning/targets/{id}/matches — what fits it now",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/buy-planning/targets/{{buyTargetId}}/matches",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "buy-planning",
                "targets",
                "{{buyTargetId}}",
                "matches"
              ]
            },
            "description": "Needs buy-planning:read. The listings on the Marketplace that fit the target\nat its track's floor (Aggressive 80, Balanced 90, Conservative exact only),\nin the app's order: exact first, then by score.\n\n200 { targetId, track, totalCount, items: [{ vehicleId, url, year, make,\nmodel, trim, mileage, state, ask, isNew, score, kind, misses }] }. A match\ncarries the listing's PUBLIC facts only: never a seller's name, id, floor,\nthresholds or limits, and no VIN. \"kind\" is EXACT at score 100 and NEAR below;\n\"misses\" say what a near match is not, in plain words. The list may be empty.\n\nHide one from this target with\nPOST /api/v1/buy-planning/targets/{id}/matches/{vehicleId}/dismiss\n(body {} to hide, { \"undo\": true } to bring it back).\n\n404 — another organization's target is \"Target not found\", as one that does\nnot exist."
          },
          "response": []
        },
        {
          "name": "POST /buy-planning/purchases — record a purchase made elsewhere",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "let body = {};",
                  "try { body = pm.response.json(); } catch (e) { /* empty response */ }",
                  "if (body.id) pm.collectionVariables.set(\"buyPurchaseId\", body.id);"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/buy-planning/purchases",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "buy-planning",
                "purchases"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"targetId\": \"{{buyTargetId}}\",\n  \"purchasedAt\": \"{{buyToday}}\",\n  \"unitPrice\": 24000,\n  \"description\": { \"year\": 2022, \"make\": \"Toyota\", \"model\": \"RAV4\", \"vin\": \"2T3W1RFV0NW000001\", \"mileage\": 31000 },\n  \"note\": \"Bought at the Orlando auction\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Needs buy-planning:write. A purchase made outside Cypress, so the plan's\nprogress is complete. \"targetId\" is the target it counts toward, or null for\na purchase outside the plan; \"purchasedAt\" is a day, up to tomorrow (UTC).\n\n201 the purchase: state FILLED (bought), source RECORDED, the vehicle as the\napp shows it. It counts toward the target (bought +1, remaining -1) and the\nquarter's progress. Captures its id.\n\nA purchase is a FACT: it is never refused for a closed quarter, on a closed\nquarter's target too. There is NO idempotency key: sending this twice\nrecords it twice. Read first (GET /api/v1/buy-planning/purchases), then\nrecord. A purchase you recorded by hand can be removed with\nDELETE /api/v1/buy-planning/purchases/{id}; PATCH moves it to another\ntarget, or to none with { \"targetId\": null }."
          },
          "response": []
        },
        {
          "name": "GET /buy-planning/quarters/{periodKey} — progress and the new digest",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "let body = {};",
                  "try { body = pm.response.json(); } catch (e) { /* empty response */ }",
                  "if (body.digest) pm.collectionVariables.set(\"buyDigest\", body.digest);"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/buy-planning/quarters/{{buyPeriodKey}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "buy-planning",
                "quarters",
                "{{buyPeriodKey}}"
              ]
            },
            "description": "Needs buy-planning:read. The quarter again: \"progress\" now counts the\npurchase from 06 (bought 1, spent 24000), and the digest is the live plan's\nafter the target of 04. An approval is bound to the digest you read, so\nread just before you approve. Captures it for 08."
          },
          "response": []
        },
        {
          "name": "POST /buy-planning/quarters/{periodKey}/approve",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/buy-planning/quarters/{{buyPeriodKey}}/approve",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "buy-planning",
                "quarters",
                "{{buyPeriodKey}}",
                "approve"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"digest\": \"{{buyDigest}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Needs buy-planning:write. The plan as it stands becomes the baseline the\napp's Review compares what happens against; the plan stays live and editable\nafterwards (read the quarter again and \"approval.changesSince\" lists what\ndiffers from the approved plan, one plain-words line each). Approving again\nmoves the baseline.\n\n200 the quarter, approved: \"approval\": { \"approvedAt\": …, \"changesSince\": [] }.\n\n409 PLAN_CHANGED — the digest is not the live plan's: the plan moved since\n07. Run 07 again, then this. 409 PERIOD_CLOSED — the quarter is over.\n409 NOTHING_TO_APPROVE — no goal, no budget and no target (run 03 and 04)."
          },
          "response": []
        },
        {
          "name": "POST /webhooks/subscriptions — hear of the buy plan",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "let body = {};",
                  "try { body = pm.response.json(); } catch (e) { /* empty response */ }",
                  "if (res.status === 201) {",
                  "  pm.collectionVariables.set(\"buySubscriptionId\", body.subscription.id);",
                  "  pm.collectionVariables.set(\"buySigningSecret\", body.signingSecret);",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/webhooks/subscriptions",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "webhooks",
                "subscriptions"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"callback\": \"https://your-endpoint.example/webhooks/cypress\",\n  \"headers\": { \"x-api-key\": \"the-secret-your-endpoint-expects\" },\n  \"emails\": [\"ops@your-company.example\"],\n  \"eventTypes\": [\"BUY.TARGET.MATCHED\", \"BUY.TARGET.FILLED\", \"BUY.TARGET.ENDED\"],\n  \"dialect\": \"CYPRESS\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Needs the webhooks scope AND buy-planning:read (buy-planning:write holds it too),\non an organization with Buy planning. The three events tell your purchasing\nsystem when the plan moves, so it does not have to poll:\n\nBUY.TARGET.MATCHED — a live listing fits an open target for the first time\n  (body: the target's id, label and quarter, and the match exactly as\n  request 05 returns it).\nBUY.TARGET.FILLED — a target has nothing left to buy (body: the target, as\n  request 04 returns it, with its bought and in-closing counts).\nBUY.TARGET.ENDED — a target's quarter closed with units still short (body:\n  the target, its shortfall and its bought count).\n\nThey are opt-in: a subscription without eventTypes never receives them. Cypress\ndialect only (a MANHEIM subscription that lists one is 422). Each is delivered\nto an endpoint once, and its body is the moment the event happened. A body\ncarries your own target and a listing's public facts only, never a seller.\n\n201 { subscription, signingSecret } — the secret is shown ONCE (kept here as\nbuySigningSecret): verify x-cypress-signature with it.\n403 SCOPE_MISSING — the key lacks buy-planning:read (or webhooks).\n403 BUY_PLANNING_NOT_ENABLED — the organization has no Buy planning.\n422 — callback must be HTTPS, or the subscription uses the MANHEIM names.\n\nTry it with 3-webhooks/03 after setting subscriptionId to buySubscriptionId;\nremove it with DELETE /api/v1/webhooks/subscriptions/{id} when you are done."
          },
          "response": []
        }
      ]
    },
    {
      "name": "offers",
      "item": [
        {
          "name": "GET /offers — the open offers on your vehicles",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "let body = {};",
                  "try { body = pm.response.json(); } catch (e) { /* empty response */ }",
                  "if (body.items && body.items[0]) pm.collectionVariables.set(\"offerId\", body.items[0].id);"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/offers?status=NEW,REVIEWED,COUNTERED",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "offers"
              ],
              "query": [
                {
                  "key": "status",
                  "value": "NEW,REVIEWED,COUNTERED"
                }
              ]
            },
            "description": "Needs offers:read (or offers:write). An API key or a Connect Cypress token.\nSince 1.5.0. Newest first, 25 to a page (limit up to 100, offset, nextHref).\nside=SELLER (the default) lists the offers on your vehicles; side=BUYER the\nones your organization made. An offer never names the buyer.\n\nCaptures the first offer's id for 02 to 06."
          },
          "response": []
        },
        {
          "name": "GET /offers/{id}",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/offers/{{offerId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "offers",
                "{{offerId}}"
              ]
            },
            "description": "One offer on your vehicle, or one you made: amount, status, counterAmount,\ncounterExpiresAt and links.app (Seller Hub for the seller, Buyer Hub for the\nbuyer). Any other offer answers 404, as one that does not exist."
          },
          "response": []
        },
        {
          "name": "POST /offers/{id}/counter?dryRun=true",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/offers/{{offerId}}/counter?dryRun=true",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "offers",
                "{{offerId}}",
                "counter"
              ],
              "query": [
                {
                  "key": "dryRun",
                  "value": "true"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"amount\": 22000,\n  \"message\": \"Fresh tires, one owner.\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Needs offers:write. Checks every rule and writes nothing: the answer is\n{ \"dryRun\": true, \"result\": { \"status\": \"WOULD_COUNTER\", ... } } or the\nrefusal the real request would get.\n\n403 PEOPLE_ONLY — a counter below the floor is a person's, in the app, for\nevery API caller. 409 CONFLICT — the offer is no longer open (NEW, REVIEWED\nor COUNTERED). 403 POLICY_DENIED — the person an app acts for may not decide\noffers."
          },
          "response": []
        },
        {
          "name": "POST /offers/{id}/counter",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "kit-counter-{{offerId}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/offers/{{offerId}}/counter",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "offers",
                "{{offerId}}",
                "counter"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"amount\": 22000,\n  \"message\": \"Fresh tires, one owner.\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Answers the buyer with your price. The buyer has 48 hours: the result\ncarries counterAmount and counterExpiresAt, and the offer is returned as it\nis now. Sends OFFERS.COUNTERED to your endpoints.\n\nIdempotency-Key: a retry with the same key and body gets the first answer\n(Idempotent-Replayed: true) instead of a second counter."
          },
          "response": []
        },
        {
          "name": "POST /offers/{id}/accept",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Idempotency-Key",
                "value": "kit-accept-{{offerId}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/offers/{{offerId}}/accept",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "offers",
                "{{offerId}}",
                "accept"
              ]
            },
            "description": "Accepts an open offer on your vehicle; the closing opens and\nOFFERS.ACCEPTED is sent. No body.\n\n403 PEOPLE_ONLY — an offer below the floor is accepted by a person in the\napp, never by an API key, an app or an agent. Try 03 with ?dryRun=true on\naccept first if you are not sure."
          },
          "response": []
        },
        {
          "name": "POST /offers/{id}/decline",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/offers/{{offerId}}/decline",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "offers",
                "{{offerId}}",
                "decline"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"reason\": \"Below what we can take this week.\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Declines an open offer on your vehicle; the buyer is told and\nOFFERS.DECLINED is sent. reason is optional (up to 500 characters).\n\nAn agent cannot decide a below-floor offer at all, a decline included\n(403 BELOW_FLOOR)."
          },
          "response": []
        },
        {
          "name": "POST /offers/{id}/withdraw (buyer side)",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/offers/{{buyerOfferId}}/withdraw",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "offers",
                "{{buyerOfferId}}",
                "withdraw"
              ]
            },
            "description": "Withdraws an open offer YOUR organization made (list them with\nGET /offers?side=BUYER and set buyerOfferId). The vehicle goes back to\nListed only when no other offer on it is still open; the seller hears\nOFFERS.WITHDRAWN. No body. 409 CONFLICT when the offer is no longer open."
          },
          "response": []
        }
      ]
    },
    {
      "name": "crm and your own ids",
      "item": [
        {
          "name": "POST /businesses — with your own id",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "let body = {};",
                  "try { body = pm.response.json(); } catch (e) { /* empty response */ }",
                  "const b = body.business; if (b) pm.collectionVariables.set(\"businessId\", b.id);"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/businesses",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "businesses"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"name\": \"Lone Star Auto Group\",\n  \"domain\": \"lonestarauto.example\",\n  \"tags\": [\n    \"dealer\"\n  ],\n  \"externalIds\": [\n    {\n      \"source\": \"my-crm\",\n      \"id\": \"B-100\"\n    }\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Needs crm:write. Since 1.5.0. Creates a business of your own book, or opens\nthe one your book already has with that name or domain (\"created\": false,\n200). externalIds are your own systems' ids: one per source.\n\n409 EXTERNAL_ID_TAKEN — the id already names another business of your\norganization; \"taken\" names it. Captures businessId."
          },
          "response": []
        },
        {
          "name": "POST /contacts — at that business",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "let body = {};",
                  "try { body = pm.response.json(); } catch (e) { /* empty response */ }",
                  "const c = body.contact; if (c) pm.collectionVariables.set(\"contactId\", c.id);"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/contacts",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "contacts"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"email\": \"maria.delgado@lonestarauto.example\",\n  \"firstName\": \"Maria\",\n  \"lastName\": \"Delgado\",\n  \"kind\": \"ORG_PROSPECT\",\n  \"businessId\": \"{{businessId}}\",\n  \"externalIds\": [\n    {\n      \"source\": \"my-crm\",\n      \"id\": \"C-101\"\n    }\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Needs crm:write. Creates a contact, or opens the one with that address.\nkind ORG_PROSPECT (someone at a company) or CONSUMER. Captures contactId."
          },
          "response": []
        },
        {
          "name": "GET /contacts?externalId=my-crm:C-101",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/contacts?externalId=my-crm:C-101",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "contacts"
              ],
              "query": [
                {
                  "key": "externalId",
                  "value": "my-crm:C-101"
                }
              ]
            },
            "description": "Every list that takes externalIds takes ?externalId=source:id, so a bridge\nlooks records up by its own ids and keeps no table of Cypress ids. The\nsame works on vehicles, listings, businesses, deals and tasks."
          },
          "response": []
        },
        {
          "name": "POST /contacts/bulk — up to 100 by your own ids",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/contacts/bulk",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "contacts",
                "bulk"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"items\": [\n    {\n      \"email\": \"james.okafor@lonestarauto.example\",\n      \"firstName\": \"James\",\n      \"lastName\": \"Okafor\",\n      \"businessId\": \"{{businessId}}\",\n      \"externalIds\": [\n        {\n          \"source\": \"my-crm\",\n          \"id\": \"C-102\"\n        }\n      ]\n    },\n    {\n      \"email\": \"maria.delgado@lonestarauto.example\",\n      \"firstName\": \"Maria\",\n      \"lastName\": \"Delgado\",\n      \"phone\": \"+1 512 555 0101\",\n      \"externalIds\": [\n        {\n          \"source\": \"my-crm\",\n          \"id\": \"C-101\"\n        }\n      ]\n    }\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Each row is the body a single POST takes, matched by its externalIds: a row\nwhose ids name a record changes it (200, as a PATCH), a row that names none\nmakes one (201), a row that names two records is refused (409\nEXTERNAL_ID_TAKEN). Rows run in order; one bad row never fails the batch.\n\nThe answer: items[] with index, status, id (or code and errors), and the\ncounts created, updated, refused. /businesses/bulk and /tasks/bulk work the\nsame way."
          },
          "response": []
        },
        {
          "name": "POST /deals",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "let body = {};",
                  "try { body = pm.response.json(); } catch (e) { /* empty response */ }",
                  "const d = body.deal; if (d) pm.collectionVariables.set(\"dealId\", d.id);"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/deals",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "deals"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"title\": \"Q4 sedans for Lone Star\",\n  \"businessId\": \"{{businessId}}\",\n  \"contactId\": \"{{contactId}}\",\n  \"expectedAmount\": 96000,\n  \"externalIds\": [\n    {\n      \"source\": \"my-crm\",\n      \"id\": \"D-100\"\n    }\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Needs crm:write. A deal belongs to a business or a contact of your book.\nIt opens in the first stage of its pipeline (GET /deals/stages lists both).\nCaptures dealId."
          },
          "response": []
        },
        {
          "name": "POST /deals/{id}/stage",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/deals/{{dealId}}/stage",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "deals",
                "{{dealId}}",
                "stage"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"stage\": \"QUALIFIED\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Moves a deal by hand, with the board's rules. A move to LOST takes a\nlostReason (and lostNote). PATCH /deals/{id} never changes the stage."
          },
          "response": []
        },
        {
          "name": "POST /contacts/{id}/notes",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/contacts/{{contactId}}/notes",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "contacts",
                "{{contactId}}",
                "notes"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"body\": \"Prefers a call before 10am. Fleet of 40, renews in March.\",\n  \"pinned\": true\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Adds a note to the contact (businesses and deals take notes the same way).\nOnly its author rewords it; its author or Cypress removes it."
          },
          "response": []
        },
        {
          "name": "POST /contacts/{id}/interactions",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/contacts/{{contactId}}/interactions",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "contacts",
                "{{contactId}}",
                "interactions"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"channel\": \"PHONE\",\n  \"direction\": \"OUTBOUND\",\n  \"subject\": \"Q4 sedan list\",\n  \"outcome\": \"CONNECTED\",\n  \"durationMinutes\": 12,\n  \"dealId\": \"{{dealId}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Logs what happened, on the contact's timeline (and the deal's, when named).\nLogging is not sending: POST /contacts/{id}/outreach emails a contact, and\nthat is a person's (an API key or an agent gets 403 PEOPLE_ONLY)."
          },
          "response": []
        }
      ]
    },
    {
      "name": "tasks and mission control",
      "item": [
        {
          "name": "GET /members — people and agents",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "let body = {};",
                  "try { body = pm.response.json(); } catch (e) { /* empty response */ }",
                  "const items = body.items || [];",
                  "const person = items.find((m) => m.kind !== 'AGENT');",
                  "const agent = items.find((m) => m.kind === 'AGENT');",
                  "if (person) pm.collectionVariables.set(\"memberUserId\", person.id);",
                  "if (agent) pm.collectionVariables.set(\"agentUserId\", agent.id);"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/members",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "members"
              ]
            },
            "description": "Needs members:read. Your members, people and agents (kind AGENT, with the\napp that added them). Captures a person as memberUserId and, when one is\nconnected, an agent as agentUserId."
          },
          "response": []
        },
        {
          "name": "POST /tasks",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "let body = {};",
                  "try { body = pm.response.json(); } catch (e) { /* empty response */ }",
                  "const t = body.task; if (t) pm.collectionVariables.set(\"taskId\", t.id);"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "kit-task-{{contactId}}-follow-up"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/tasks",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "tasks"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"title\": \"Call Maria back about the Q4 sedans\",\n  \"contactId\": \"{{contactId}}\",\n  \"dueDate\": \"2026-11-02T15:00:00Z\",\n  \"channel\": \"PHONE\",\n  \"playKey\": \"follow-up\",\n  \"externalIds\": [\n    {\n      \"source\": \"my-crm\",\n      \"id\": \"T-1\"\n    }\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Needs tasks:write. Since 1.5.0. A task belongs to something of your\norganization (a contact, company, deal, vehicle, sell goal, window or lot,\nor buy target); a task about nothing is 422. An API key's task reads as an\nautomation's and is unassigned unless you name someone. Sends\nTASK.CREATED. Captures taskId."
          },
          "response": []
        },
        {
          "name": "GET /tasks?status=OPEN",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/tasks?status=OPEN&contactId={{contactId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "tasks"
              ],
              "query": [
                {
                  "key": "status",
                  "value": "OPEN"
                },
                {
                  "key": "contactId",
                  "value": "{{contactId}}"
                }
              ]
            },
            "description": "Soonest due first, undated last. Filters combine (status, source, assignee,\ndueAfter, dueBefore, the record ids, playKey, externalId); an unknown filter\nis 422, so a typo never returns everything. assignee=me needs a token."
          },
          "response": []
        },
        {
          "name": "POST /tasks/{id}/reassign",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/tasks/{{taskId}}/reassign",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "tasks",
                "{{taskId}}",
                "reassign"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"assigneeUserId\": \"{{memberUserId}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Gives the task to an active member of your organization, person or agent\n(null: to nobody). Sends TASK.ASSIGNED when it goes to someone other than\nthe caller."
          },
          "response": []
        },
        {
          "name": "POST /tasks/{id}/complete",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/tasks/{{taskId}}/complete",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "tasks",
                "{{taskId}}",
                "complete"
              ]
            },
            "description": "Marks it done and records who finished it. Sends TASK.COMPLETED."
          },
          "response": []
        },
        {
          "name": "GET /mission-control",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "let body = {};",
                  "try { body = pm.response.json(); } catch (e) { /* empty response */ }",
                  "if (body.items && body.items[0]) pm.collectionVariables.set(\"missionItemId\", body.items[0].id);"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/mission-control?urgency=decision,overdue",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "mission-control"
              ],
              "query": [
                {
                  "key": "urgency",
                  "value": "decision,overdue"
                }
              ]
            },
            "description": "Needs mission-control:read. What needs a person now, most urgent first,\nfrom every system that owns some of it (offers, closings, onboarding,\nvaluations, billing, campaigns, the CRM), with a summary. urgency is one or\nmore of decision, overdue, due-soon, attention, fyi. Captures the first\nitem as missionItemId."
          },
          "response": []
        },
        {
          "name": "POST /mission-control/items/{itemId}/delegate",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/mission-control/items/{{missionItemId}}/delegate",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "mission-control",
                "items",
                "{{missionItemId}}",
                "delegate"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"agentUserId\": \"{{agentUserId}}\",\n  \"note\": \"Check the floor before you answer\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Needs mission-control:read and tasks:write. Gives the item to one of your\nagents as a task. Without agentUserId it goes to your only agent; with none\nconnected, or several and none named, it is refused and says which."
          },
          "response": []
        }
      ]
    },
    {
      "name": "closings and notifications",
      "item": [
        {
          "name": "GET /closings?yourTurn=true",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "let body = {};",
                  "try { body = pm.response.json(); } catch (e) { /* empty response */ }",
                  "if (body.items && body.items[0]) pm.collectionVariables.set(\"closingId\", body.items[0].id);"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/closings?status=IN_PROGRESS&yourTurn=true",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "closings"
              ],
              "query": [
                {
                  "key": "status",
                  "value": "IN_PROGRESS"
                },
                {
                  "key": "yourTurn",
                  "value": "true"
                }
              ]
            },
            "description": "Needs closing:read. Since 1.5.0. The closings your organization is a party\nto, as your side (SELLER or BUYER) sees them: each step with who carries its\ndeadline, whose turn it is, the deadline and whether it is late. No money\ndetail; the other party by its company name only. Captures closingId."
          },
          "response": []
        },
        {
          "name": "GET /closings/{id}",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "let body = {};",
                  "try { body = pm.response.json(); } catch (e) { /* empty response */ }",
                  "const c = body.closing;",
                  "if (c) {",
                  "  if (c.currentStep) pm.collectionVariables.set(\"stepKey\", c.currentStep);",
                  "  const open = (c.requirements || []).find((r) => !r.satisfied && !r.waived);",
                  "  if (open) pm.collectionVariables.set(\"requirementId\", open.id);",
                  "  for (const s of c.steps || []) for (const d of s.documents || []) {",
                  "    const sig = (d.signatures || []).find((x) => x.signingLink);",
                  "    if (sig) { pm.collectionVariables.set(\"documentId\", d.id); pm.collectionVariables.set(\"signerParty\", sig.party); }",
                  "  }",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/closings/{{closingId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "closings",
                "{{closingId}}"
              ]
            },
            "description": "Key off step keys (FEE, BOS, CONFIRM_FUNDS, GATE_PASS, TITLE, PICKUP), never\nthe number. currentStep is the first open step holding it up; requirements\nlists the documents it needs. Captures stepKey, a requirement still lacking\n(requirementId) and one of your side's signatures (documentId, signerParty)."
          },
          "response": []
        },
        {
          "name": "POST /closings/{id}/steps/{stepKey}/remind",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Idempotency-Key",
                "value": "kit-remind-{{closingId}}-{{stepKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/closings/{{closingId}}/steps/{{stepKey}}/remind",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "closings",
                "{{closingId}}",
                "steps",
                "{{stepKey}}",
                "remind"
              ]
            },
            "description": "Needs closing:write. Reminds whoever's turn the step is. Changes no step.\nAgain after an hour: a 409 carries retryAfter. ?dryRun=true says who would\nhear it."
          },
          "response": []
        },
        {
          "name": "POST /closings/{id}/document-requests",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/closings/{{closingId}}/document-requests",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "closings",
                "{{closingId}}",
                "document-requests"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"requirementId\": \"{{requirementId}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Asks whoever does the requirement's step for the document. Both sides'\nsystems also get CLOSING.DOCUMENT.REQUESTED. Again after an hour."
          },
          "response": []
        },
        {
          "name": "POST /closings/{id}/documents/{documentId}/signatures/{party}/resend",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/closings/{{closingId}}/documents/{{documentId}}/signatures/{{signerParty}}/resend",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "closings",
                "{{closingId}}",
                "documents",
                "{{documentId}}",
                "signatures",
                "{{signerParty}}",
                "resend"
              ]
            },
            "description": "Emails a signer their link again, from Cypress's signing service. Signing\ngoes in order (seller, then buyer, on the base Bill of Sale), so a link is\nnot re-sent before its signer's turn. Again after ten minutes."
          },
          "response": []
        },
        {
          "name": "GET /notifications",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/notifications?limit=20",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "notifications"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "20"
                }
              ]
            },
            "description": "Needs notifications:read. Since 1.5.0. What Cypress told your members,\npeople and agents, newest first, each with its recipient. Page with\nbefore=nextCursor while hasMore. The same notices arrive as\nNOTIFICATION.CREATED to a subscription that lists it."
          },
          "response": []
        },
        {
          "name": "GET /notifications/preferences?userId=",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/notifications/preferences?userId={{memberUserId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "notifications",
                "preferences"
              ],
              "query": [
                {
                  "key": "userId",
                  "value": "{{memberUserId}}"
                }
              ]
            },
            "description": "Needs notifications:write. The notifications a person may switch off, each\nwith its workflow and its email and inApp channels. An API key names any\nactive person; an app acting for a person reads that person's (leave userId\nout). An agent has none: 403 PEOPLE_ONLY."
          },
          "response": []
        },
        {
          "name": "PATCH /notifications/preferences",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/notifications/preferences",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "notifications",
                "preferences"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"userId\": \"{{memberUserId}}\",\n  \"workflow\": \"offer.received\",\n  \"channels\": {\n    \"email\": false\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Sets one workflow's channels for one person. A notification Cypress marks\nas one that cannot be switched off, or a name not on the list, is 422.\nRecorded in your audit log with the key or app that made it."
          },
          "response": []
        }
      ]
    },
    {
      "name": "marketing",
      "item": [
        {
          "name": "GET /message-templates",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/message-templates",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "message-templates"
              ]
            },
            "description": "Needs marketing:read. Since 1.5.0. Your message templates and Cypress's base library."
          },
          "response": []
        },
        {
          "name": "POST /campaigns — always a draft",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "let body = {};",
                  "try { body = pm.response.json(); } catch (e) { /* empty response */ }",
                  "const c = body.campaign; if (c) pm.collectionVariables.set(\"campaignId\", c.id);"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/campaigns",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "campaigns"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"name\": \"Fresh RAV4s\",\n  \"content\": \"MESSAGE\",\n  \"subject\": \"New RAV4s this week\",\n  \"body\": \"Three clean trade-ins just landed.\",\n  \"audience\": {\n    \"source\": \"crm\",\n    \"crm\": {\n      \"tags\": [\n        \"vip\"\n      ]\n    }\n  },\n  \"schedule\": {\n    \"frequency\": \"WEEKLY\",\n    \"daysOfWeek\": [\n      2\n    ],\n    \"hour\": 9\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Needs marketing:write. Your own people only: audience source \"crm\" (your\nbook, narrowed by tags and the rest) or \"subscribers\". A pasted list of\naddresses (\"email-list\") is a person's choice in the app: 403 PEOPLE_ONLY\nfrom any API caller. Captures campaignId."
          },
          "response": []
        },
        {
          "name": "GET /campaigns",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/campaigns?status=ACTIVE",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "campaigns"
              ],
              "query": [
                {
                  "key": "status",
                  "value": "ACTIVE"
                }
              ]
            },
            "description": "Newest first, with the PEOPLE each reached: \"reached\" counts people, never\nrows, and a suppressed address is never sent to."
          },
          "response": []
        },
        {
          "name": "POST /campaigns/{id}/activate",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/campaigns/{{campaignId}}/activate",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "campaigns",
                "{{campaignId}}",
                "activate"
              ]
            },
            "description": "Activates (or resumes) the campaign on its schedule. A person's for an\nagent: an agent drafts and pauses campaigns, and gets 403 PEOPLE_ONLY here\nand on /send. An API key may."
          },
          "response": []
        },
        {
          "name": "GET /campaigns/{id}/sends",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/campaigns/{{campaignId}}/sends",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "campaigns",
                "{{campaignId}}",
                "sends"
              ]
            },
            "description": "Each send, in people. CAMPAIGN.SENT announces one to a subscription that lists it."
          },
          "response": []
        },
        {
          "name": "GET /campaigns/{id}/interest",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/campaigns/{{campaignId}}/interest",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "campaigns",
                "{{campaignId}}",
                "interest"
              ]
            },
            "description": "Your cars the campaign brought people to. CAMPAIGN.INTEREST announces each."
          },
          "response": []
        },
        {
          "name": "POST /campaigns/{id}/pause",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/campaigns/{{campaignId}}/pause",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "campaigns",
                "{{campaignId}}",
                "pause"
              ]
            },
            "description": "Pauses it. Anyone with marketing:write may, an agent included. Sends CAMPAIGN.PAUSED."
          },
          "response": []
        }
      ]
    },
    {
      "name": "automations",
      "item": [
        {
          "name": "GET /automation/manifest",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/automation/manifest",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "automation",
                "manifest"
              ]
            },
            "description": "Since 1.5.0. Cypress's domain as data: the records, events and lookups an\nautomation can use, and the acts your credential's scopes allow, each with\nthe node that runs it. Cached: send If-None-Match to get 304."
          },
          "response": []
        },
        {
          "name": "POST /automations",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "let body = {};",
                  "try { body = pm.response.json(); } catch (e) { /* empty response */ }",
                  "const a = body.automation; if (a) pm.collectionVariables.set(\"automationId\", a.id);"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/automations",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "automations"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"name\": \"Stale listing nudge\",\n  \"category\": \"LISTING\",\n  \"graph\": {\n    \"nodes\": [\n      { \"id\": \"start\", \"type\": \"trigger\", \"position\": { \"x\": 0, \"y\": 0 },\n        \"data\": { \"nodeType\": \"ENTITY_TIME_ELAPSED\", \"label\": \"30 days listed\",\n                  \"config\": { \"entity\": \"vehicle\", \"watchStatus\": \"LISTED\", \"duration\": 30, \"unit\": \"days\" } } },\n      { \"id\": \"note\", \"type\": \"action\", \"position\": { \"x\": 0, \"y\": 120 },\n        \"data\": { \"nodeType\": \"CREATE_TASK\", \"label\": \"Leave a note\",\n                  \"config\": { \"note\": \"Listed 30 days: review the price\" } } }\n    ],\n    \"edges\": [{ \"id\": \"e1\", \"source\": \"start\", \"target\": \"note\" }]\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Needs automations:write, on an organization with the Automations product\n(else 403 AUTOMATIONS_NOT_ENABLED, asked before the scopes). Creates the\nautomation with its first draft. Nothing runs until a Cypress manager\npublishes it. Captures automationId."
          },
          "response": []
        },
        {
          "name": "POST /automations/{id}/validate",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/automations/{{automationId}}/validate",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "automations",
                "{{automationId}}",
                "validate"
              ]
            },
            "description": "What publishing would say: errors would stop Cypress publishing it; warnings are the editor's advice."
          },
          "response": []
        },
        {
          "name": "POST /automations/{id}/dry-run",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "let body = {};",
                  "try { body = pm.response.json(); } catch (e) { /* empty response */ }",
                  "if (body.runs && body.runs[0]) pm.collectionVariables.set(\"runId\", body.runs[0].id);"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/automations/{{automationId}}/dry-run",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "automations",
                "{{automationId}}",
                "dry-run"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"subjectIds\": [\n    \"{{vehicleId}}\"\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Every step runs as the automation would and writes nothing; a step the\nrules refuse shows as refused. One run per record (up to 25), the draft by\ndefault. 202 with the runs; captures the first runId. An agent may try\nautomations."
          },
          "response": []
        },
        {
          "name": "GET /automations/runs/{runId}/steps",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/automations/runs/{{runId}}/steps?limit=100",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "automations",
                "runs",
                "{{runId}}",
                "steps"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "100"
                }
              ]
            },
            "description": "The run's steps in the order they ran, each with what it did or why it was refused. A run reads QUEUED until the worker starts it."
          },
          "response": []
        },
        {
          "name": "POST /automations/{id}/submit",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/automations/{{automationId}}/submit",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "automations",
                "{{automationId}}",
                "submit"
              ]
            },
            "description": "Asks Cypress to publish the draft. 202. AUTOMATION.PUBLISHED or\nAUTOMATION.SENT_BACK (with the manager's note) tells you the answer."
          },
          "response": []
        },
        {
          "name": "POST /automations/{id}/deactivate",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/automations/{{automationId}}/deactivate",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "automations",
                "{{automationId}}",
                "deactivate"
              ]
            },
            "description": "Switches it off. Switching one back on (/activate) is a person's for an\nagent (403 PEOPLE_ONLY); an API key may."
          },
          "response": []
        },
        {
          "name": "GET /automations/{id}/runs",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/automations/{{automationId}}/runs",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "automations",
                "{{automationId}}",
                "runs"
              ]
            },
            "description": "Newest first; filter with status. AUTOMATION.RUN.COMPLETED and AUTOMATION.RUN.FAILED announce them."
          },
          "response": []
        }
      ]
    },
    {
      "name": "planning the quarter",
      "item": [
        {
          "name": "POST /planning/strategy — the sell draft in one call",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/planning/strategy",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "planning",
                "strategy"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"name\": \"Q4 balanced\",\n  \"objective\": \"BALANCED_RENEWAL\",\n  \"goals\": [\n    {\n      \"params\": {\n        \"kind\": \"UNITS\",\n        \"units\": 12\n      }\n    },\n    {\n      \"params\": {\n        \"kind\": \"CASH\",\n        \"amount\": 250000,\n        \"byDate\": \"2026-12-31\"\n      }\n    }\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Needs planning:write, on an organization with Planning. Since 1.5.0. Sets\nthe mandate: the active strategy retires (its history stays), plan v1 is\nmade and the whole fleet is enrolled; with goals, the quarter's goals are\nadded in the same call. A goal that is refused does not undo the strategy:\n\"goals\" lists each as written, or its error and code. The app's \"Plan my\nquarter with Sequoia\" makes these calls."
          },
          "response": []
        },
        {
          "name": "GET /planning/quarters/current",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "let body = {};",
                  "try { body = pm.response.json(); } catch (e) { /* empty response */ }",
                  "if (body.period) pm.collectionVariables.set(\"sellPeriodKey\", body.period.periodKey);",
                  "if (body.approvalDigest) pm.collectionVariables.set(\"sellDigest\", body.approvalDigest);"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/planning/quarters/current",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "planning",
                "quarters",
                "current"
              ]
            },
            "description": "The quarter: goals and their attainment, lots per month, windows with their\nhand-to-Sell dates, the fleet's shape, and approvalDigest. periodKey is\n2026-Q4 or current. Captures sellPeriodKey and sellDigest."
          },
          "response": []
        },
        {
          "name": "POST /planning/schedule/proposals",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "let body = {};",
                  "try { body = pm.response.json(); } catch (e) { /* empty response */ }",
                  "if (body.digest) {",
                  "  pm.collectionVariables.set(\"schedulePeriodId\", body.periodId);",
                  "  pm.collectionVariables.set(\"scheduleDigest\", body.digest);",
                  "  pm.collectionVariables.set(\"scheduleExpiresAt\", body.expiresAt);",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/planning/schedule/proposals",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "planning",
                "schedule",
                "proposals"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"periodKey\": \"{{sellPeriodKey}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Which vehicles into which windows, and why, and what could not be placed.\nWrites nothing. Good for 24 hours. Captures what 04 sends back."
          },
          "response": []
        },
        {
          "name": "POST /planning/schedule/apply",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "kit-schedule-{{scheduleDigest}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/planning/schedule/apply",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "planning",
                "schedule",
                "apply"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"periodId\": \"{{schedulePeriodId}}\",\n  \"digest\": \"{{scheduleDigest}}\",\n  \"expiresAt\": \"{{scheduleExpiresAt}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Applies the proposal (add \"vehicleIds\" for some lines only): one plan\nversion. 409 PREVIEW_STALE — the plan changed since 03 or the proposal is\nolder than 24 hours: ask again."
          },
          "response": []
        },
        {
          "name": "POST /planning/quarters/{periodKey}/approve — a person's",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/planning/quarters/{{sellPeriodKey}}/approve",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "planning",
                "quarters",
                "{{sellPeriodKey}}",
                "approve"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"digest\": \"{{sellDigest}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "The approved plan becomes the baseline. Run 02 again first: the digest must\nbe the live plan's (409 PREVIEW_STALE otherwise). An agent's token gets\n403 PEOPLE_ONLY: an agent prepares the plan, a person approves it. An API\nkey or an app acting for a person may. 409 PERIOD_CLOSED for a quarter\nthat is over."
          },
          "response": []
        },
        {
          "name": "POST /buy-planning/drafts",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "let body = {};",
                  "try { body = pm.response.json(); } catch (e) { /* empty response */ }",
                  "if (body.targets) {",
                  "  pm.collectionVariables.set(\"buyDraftTargets\", JSON.stringify(body.targets));",
                  "  pm.collectionVariables.set(\"buyDraftUnits\", JSON.stringify(body.unitsGoal ?? null));",
                  "  pm.collectionVariables.set(\"buyDraftBudget\", JSON.stringify(body.budget ?? null));",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/buy-planning/drafts",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "buy-planning",
                "drafts"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"mandate\": \"USUAL_MIX\",\n  \"periodKey\": \"{{buyPeriodKey}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Needs buy-planning:write, on an organization with Buy planning. Sequoia's\ndraft of a quarter: a units goal, a budget and the targets it would keep,\nwith its basis in words. Writes nothing. The app's \"Plan my quarter\" for the\nBuy plan. Captures the draft's goal, budget and targets for 07."
          },
          "response": []
        },
        {
          "name": "POST /buy-planning/drafts/apply",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "kit-buy-draft-{{buyPeriodKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/buy-planning/drafts/apply",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "buy-planning",
                "drafts",
                "apply"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"periodKey\": \"{{buyPeriodKey}}\",\n  \"mandate\": \"USUAL_MIX\",\n  \"unitsGoal\": {{buyDraftUnits}},\n  \"budget\": {{buyDraftBudget}},\n  \"states\": [\"TX\", \"OK\"],\n  \"targets\": {{buyDraftTargets}}\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Keeps a draft in one step: the quarter's goal, budget and mandate, the\nplan's markets and the kept targets. This sends 06's draft back whole;\ndrop a target from the list to leave it out. 201.\n\n\"approve\": true approves the quarter too, and is a person's: an agent's\ntoken gets 403 PEOPLE_ONLY and nothing is written."
          },
          "response": []
        }
      ]
    },
    {
      "name": "events connections and insights",
      "item": [
        {
          "name": "POST /webhooks/subscriptions — the 1.5.0 events",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "let body = {};",
                  "try { body = pm.response.json(); } catch (e) { /* empty response */ }",
                  "if (body.subscription) pm.collectionVariables.set(\"eventsSubscriptionId\", body.subscription.id);"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/webhooks/subscriptions",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "webhooks",
                "subscriptions"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"callback\": \"https://your-endpoint.example/webhooks/cypress\",\n  \"dialect\": \"CYPRESS\",\n  \"eventTypes\": [\n    \"TASK.CREATED\",\n    \"TASK.ASSIGNED\",\n    \"TASK.COMPLETED\",\n    \"NOTIFICATION.CREATED\",\n    \"CLOSING.STEP.DUE\",\n    \"CLOSING.STEP.OVERDUE\",\n    \"CLOSING.DOCUMENT.REQUESTED\",\n    \"CAMPAIGN.SENT\",\n    \"CONTACT.UNSUBSCRIBED\",\n    \"AUTOMATION.RUN.FAILED\",\n    \"CONTACT.CREATED\",\n    \"CONTACT.UPDATED\",\n    \"DEAL.STAGE_CHANGED\",\n    \"OUTREACH.LOGGED\",\n    \"INSIGHT.CREATED\"\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Needs webhooks and each family's read scope (tasks:read,\nnotifications:read, closing:read, marketing:read, automations:read,\ncrm:read, insights:read). The plan's PLAN.GOAL.SET / QUARTER.APPROVED and\nBUY.TARGET.CREATED / DUE / QUARTER.APPROVED follow the planning terms. The\n1.5.0 families are opt-in: only a CYPRESS-dialect subscription that lists\nthem receives them, never an unfiltered one. Add \"entityIds\" to hear about\nsome records only. signingSecret is returned once. Put your own HTTPS\nendpoint in callback (or the kit's webhook-receiver.mjs behind a tunnel)."
          },
          "response": []
        },
        {
          "name": "GET /events — after a cursor",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "let body = {};",
                  "try { body = pm.response.json(); } catch (e) { /* empty response */ }",
                  "const ev = body.events || [];",
                  "if (ev.length) pm.collectionVariables.set(\"eventCursor\", ev[0].cursor);"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/events?limit=100",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "events"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "100"
                }
              ]
            },
            "description": "Every event a subscription can receive, kept 30 days, oldest first. Send\nafter=<your last cursor> to catch up after downtime; page with nextCursor\nwhile hasMore; types filters. Dedupe on cursor: a replay or a retry carries\nthe same one. Captures the first event's cursor for 03."
          },
          "response": []
        },
        {
          "name": "POST /webhooks/subscriptions/{id}/replay",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/webhooks/subscriptions/{{eventsSubscriptionId}}/replay",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "webhooks",
                "subscriptions",
                "{{eventsSubscriptionId}}",
                "replay"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"after\": \"{{eventCursor}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Queues the stored events after that cursor to this one subscription,\nunder their original cursors. Its filters apply. 202."
          },
          "response": []
        },
        {
          "name": "GET /connections",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/connections",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "connections"
              ]
            },
            "description": "Needs members:read. The apps connected through Connect Cypress, with their\nscopes and agents. DELETE /connections/{id} (connections:write, API keys\nonly) disconnects one: every token ends and its agents are switched off."
          },
          "response": []
        },
        {
          "name": "GET /insights?vehicleId=",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "x-api-key",
                "value": "{{apiKey}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/insights?vehicleId={{vehicleId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "insights"
              ],
              "query": [
                {
                  "key": "vehicleId",
                  "value": "{{vehicleId}}"
                }
              ]
            },
            "description": "Needs insights:read. Cedar's and Sequoia's insights on one of your vehicles\n(or targetId= for a buy target), each with what it rests on, how sure it is\nand the guardrail that applied. GET /vehicles/{id}?include=insights adds\nthem to a single read."
          },
          "response": []
        }
      ]
    }
  ]
}