# Pricefy API > Welcome developers, partners, and innovators! We are thrilled to introduce you to the Pricefy API — the backbone of our industry-leading Software as a Service (SaaS) solution. Whether you're looking to integrate Pricefy with your existing platforms, extract insightful data, or simply customize Pricefy to better fit your organization's needs, this documentation is your comprehensive guide. Base URL: `https://api.pricefy.io`. Authentication: - REST endpoints: send the `X-Api-Key` header on every request. - MCP endpoint (`POST /mcp`): accepts either `X-Api-Key` (Claude Desktop, Cursor, Codex, …) or OAuth Bearer (ChatGPT custom connectors). See `/docs` for the connection guide. ## OpenAPI - [OpenAPI specification (YAML)](https://api.pricefy.io/openapi.yaml) - [Interactive API reference](https://api.pricefy.io/docs) - [Full content as plain text](https://api.pricefy.io/llms-full.txt) ## Welcome Health check. - [Health check](https://api.pricefy.io/docs?tag=Welcome&op=welcome): `GET /v1` ## Account Merchant account, subscription and plan limits. - [Get account](https://api.pricefy.io/docs?tag=Account&op=getMerchantAccount): `GET /v1/merchant/account` ## Store Store information and last import. - [Get store](https://api.pricefy.io/docs?tag=Store&op=getMerchantStore): `GET /v1/merchant/store` ## Products Merchant product catalog. Cursor-based pagination. - [List products](https://api.pricefy.io/docs?tag=Products&op=listProducts): `GET /v1/merchant/products` - [Upsert products (bulk)](https://api.pricefy.io/docs?tag=Products&op=bulkUpsertProducts): `PUT /v1/merchant/products` - [Get product](https://api.pricefy.io/docs?tag=Products&op=getProduct): `GET /v1/merchant/products/{sku}` - [Upsert product](https://api.pricefy.io/docs?tag=Products&op=upsertProduct): `PUT /v1/merchant/products/{sku}` - [Delete product](https://api.pricefy.io/docs?tag=Products&op=deleteProduct): `DELETE /v1/merchant/products/{sku}` ## Competitors Competitor domains with price analysis. - [List competitors](https://api.pricefy.io/docs?tag=Competitors&op=listCompetitors): `GET /v1/competitors` - [Add competitor](https://api.pricefy.io/docs?tag=Competitors&op=addCompetitor): `POST /v1/competitors` - [Update competitor status](https://api.pricefy.io/docs?tag=Competitors&op=updateCompetitorStatus): `PUT /v1/competitors` - [Get competitor](https://api.pricefy.io/docs?tag=Competitors&op=getCompetitor): `GET /v1/competitors/{domain}` ## Monitored URLs URLs being monitored on each competitor, with stock and price diff. - [List monitored URLs](https://api.pricefy.io/docs?tag=Monitored%20URLs&op=listMonitoredUrls): `GET /v1/competitors/urls` - [Upsert monitored URLs](https://api.pricefy.io/docs?tag=Monitored%20URLs&op=upsertMonitoredUrls): `PUT /v1/competitors/urls` - [Delete monitored URLs](https://api.pricefy.io/docs?tag=Monitored%20URLs&op=deleteMonitoredUrls): `DELETE /v1/competitors/urls` - [Monitored URL price-history detail](https://api.pricefy.io/docs?tag=Monitored%20URLs&op=getMonitoredUrlDetail): `GET /v1/competitors/urls/detail` ## MAP Infringements Minimum Advertised Price rules and the resellers that breach them. - [List MAP infringements](https://api.pricefy.io/docs?tag=MAP%20Infringements&op=listMapInfringements): `GET /v1/map-infringements` - [List MAP infringement rules](https://api.pricefy.io/docs?tag=MAP%20Infringements&op=listMapInfringementRules): `GET /v1/map-infringement-rules` ## Repricing Dynamic pricing rules and repricing previews. - [List repricing rules](https://api.pricefy.io/docs?tag=Repricing&op=listRepricingRules): `GET /v1/dynamic-pricing/list` - [Repricing preview](https://api.pricefy.io/docs?tag=Repricing&op=getRepricingPreview): `GET /v1/dynamic-pricing/preview` - [Apply suggested prices](https://api.pricefy.io/docs?tag=Repricing&op=applyRepricing): `POST /v1/dynamic-pricing/apply/{rule_id}` ## Reports Scheduled reports configuration. - [List reports](https://api.pricefy.io/docs?tag=Reports&op=listReports): `GET /v1/reports` - [Get report](https://api.pricefy.io/docs?tag=Reports&op=getReport): `GET /v1/reports/{id}` ## Alerts Alert rules and triggered alerts (price/stock variations). - [List alert rules](https://api.pricefy.io/docs?tag=Alerts&op=listAlertRules): `GET /v1/alert-rules` - [Get alert rule](https://api.pricefy.io/docs?tag=Alerts&op=getAlertRule): `GET /v1/alert-rules/{id}` - [Get alert rule alerts](https://api.pricefy.io/docs?tag=Alerts&op=getAlertRuleAlerts): `GET /v1/alert-rules/{id}/alerts` - [List alert variations](https://api.pricefy.io/docs?tag=Alerts&op=listAlerts): `GET /v1/alerts` ## Postman Postman The **complete Pricefy API collection** lives in the [public Pricefy Postman workspace](https://www.postman.com/pricefy/workspace/pricefy-api) — every endpoint, request body, query parameter and response example, pre-wired and ready to send. Use it to explore the API in Postman desktop / web, fork it into your own workspace, or run it as part of an automated test suite via Newman. [![Run in Postman](https://run.pstmn.io/button.svg)](https://www.postman.com/pricefy/workspace/pricefy-api) Alternatives: - [Browse the workspace](https://www.postman.com/pricefy/workspace/pricefy-api) directly on postman.com - [Download the collection JSON](/postman/collection.json) and import manually into Postman or Newman - [Download the Postman collection](https://api.pricefy.io/docs?tag=Postman&op=downloadPostmanCollection): `GET /postman/collection.json` ## MCP **Model Context Protocol** — same Pricefy API, exposed as MCP tools so Claude Desktop, Cursor, ChatGPT, Codex and the Claude CLI can call it natively. Streamable HTTP transport, JSON-RPC 2.0, dual auth (`X-Api-Key` **or** OAuth 2.1 Bearer), same per-merchant permissions as REST. 25 tools (18 read-only + 5 write + 2 destructive). See `POST /mcp` for the full catalog and the landing page for connection guides. - [MCP server (Streamable HTTP JSON-RPC)](https://api.pricefy.io/docs?tag=MCP&op=mcpServer): `POST /mcp` ## Full OpenAPI specification The full machine-readable specification (YAML) is inlined below. ```yaml openapi: "3.0.0" info: version: "3.10.4" title: "Pricefy API" description: | Monitor your competitors' prices on autopilot. ## Authentication REST endpoints require the `X-Api-Key` header. The MCP endpoint (`POST /mcp`) accepts **two** authentication modes — see the dedicated **MCP** section below. ## Rate Limiting API requests are rate limited based on your subscription plan. ## Pagination Paginated endpoints use `page` + `limit` (default 25, max 100). Products use cursor-based pagination. ## Error Codes | Code | Description | |------|-------------| | 109 | Monitored URLs limit exceeded | ## Postman collection The full API is also available in the [public Pricefy Postman workspace](https://www.postman.com/pricefy/workspace/pricefy-api). Open it online, fork it into your own workspace and start sending requests in seconds. [![Run in Postman](https://run.pstmn.io/button.svg)](https://www.postman.com/pricefy/workspace/pricefy-api) ## MCP support (Model Context Protocol) The Pricefy API is also exposed as an **MCP server** at `POST /mcp` (Streamable HTTP transport), so AI clients like Claude Desktop, Cursor, ChatGPT, Codex, and the Claude CLI can call it as native tools. **25 tools** are exposed (18 read-only + 5 write + 2 destructive). Write and destructive tools are annotated so MCP clients can show a confirmation dialog before invoking them; only the two destructive tools (`delete_product`, `batch_delete_monitored_urls`) permanently remove data. Read-only ones include `list_products`, `list_competitors`, `list_monitored_urls`, `get_monitored_url_detail`, `list_alerts`, `get_account`, `get_report`, etc. Write ones include `upsert_product`, `bulk_upsert_products`, `add_competitor`. You can connect Pricefy to your AI client in two ways — pick whichever your client supports: | Method | When to use it | |---|---| | **API key** | Claude Desktop, Cursor, Codex, `claude mcp add` — any client where you can paste your Pricefy API key into a custom header. | | **OAuth** | ChatGPT custom connectors and any other client that doesn't let you set a custom header. You sign in with your Pricefy account and choose what the AI can do on a permission screen. | Either way, permissions are honored at every tool call: a read-only authorization can never trigger a write or destructive tool. ### Connect Claude Desktop or Cursor (API key) ```json { "mcpServers": { "pricefy": { "type": "http", "url": "https://api.pricefy.io/mcp", "headers": { "X-Api-Key": "YOUR_PRICEFY_API_KEY" } } } } ``` ### Connect via the `claude` CLI (API key) ```bash claude mcp add pricefy https://api.pricefy.io/mcp \ --transport http \ --header "X-Api-Key: YOUR_PRICEFY_API_KEY" ``` ### Connect ChatGPT custom connector (OAuth) Available on ChatGPT plans that include custom connectors (Plus / Pro / Business / Enterprise / Edu). In ChatGPT: 1. Settings → **Connectors** → **Advanced** → enable **Developer Mode** 2. Click **New App** and fill in: - **Name**: `Pricefy` - **MCP Server URL**: `https://api.pricefy.io/mcp` - **Authentication**: `OAuth` 3. Click **Create**. 4. ChatGPT opens a Pricefy sign-in page in your browser. Sign in with your usual Pricefy credentials, choose what ChatGPT can do for each permission group on the consent screen, then click **Allow**. 5. You're back in ChatGPT — the 25 Pricefy tools are now available. Each OAuth connection appears in **[dashboard.pricefy.io → Settings → API Keys](https://dashboard.pricefy.io/settings/api-key)** with an "OAuth" badge and a timestamped label such as `MCP Integration ChatGPT 2026-05-22-14-32-07`. To revoke a connection, just toggle it off (or delete it) from that page — the AI immediately loses access on its next call. > Companion files for AI/LLM consumers: [`/llms.txt`](/llms.txt) (lightweight index) and [`/llms-full.txt`](/llms-full.txt) (full spec inlined), generated server-side from this OpenAPI document. servers: - url: "https://api.pricefy.io" description: Production tags: - name: Welcome description: Health check. - name: Account description: Merchant account, subscription and plan limits. - name: Store description: Store information and last import. - name: Products description: Merchant product catalog. Cursor-based pagination. - name: Competitors description: Competitor domains with price analysis. - name: Monitored URLs description: URLs being monitored on each competitor, with stock and price diff. - name: MAP Infringements description: Minimum Advertised Price rules and the resellers that breach them. - name: Repricing description: Dynamic pricing rules and repricing previews. - name: Reports description: Scheduled reports configuration. - name: Alerts description: Alert rules and triggered alerts (price/stock variations). - name: MCP description: | **Model Context Protocol** — same Pricefy API, exposed as MCP tools so Claude Desktop, Cursor, ChatGPT, Codex and the Claude CLI can call it natively. Streamable HTTP transport, JSON-RPC 2.0, dual auth (`X-Api-Key` **or** OAuth 2.1 Bearer), same per-merchant permissions as REST. 25 tools (18 read-only + 5 write + 2 destructive). See `POST /mcp` for the full catalog and the landing page for connection guides. - name: Postman description: | Postman The **complete Pricefy API collection** lives in the [public Pricefy Postman workspace](https://www.postman.com/pricefy/workspace/pricefy-api) — every endpoint, request body, query parameter and response example, pre-wired and ready to send. Use it to explore the API in Postman desktop / web, fork it into your own workspace, or run it as part of an automated test suite via Newman. [![Run in Postman](https://run.pstmn.io/button.svg)](https://www.postman.com/pricefy/workspace/pricefy-api) Alternatives: - [Browse the workspace](https://www.postman.com/pricefy/workspace/pricefy-api) directly on postman.com - [Download the collection JSON](/postman/collection.json) and import manually into Postman or Newman paths: /v1: get: summary: Health check operationId: welcome tags: [Welcome] responses: 200: description: A message greeting the merchant content: application/json: schema: $ref: "#/components/schemas/SuccessfulOperation" 401: $ref: "#/components/responses/Unauthorized" /v1/merchant/account: get: summary: Get account operationId: getMerchantAccount tags: [Account] responses: 200: description: Account information for the merchant content: application/json: schema: $ref: "#/components/schemas/Account" 401: $ref: "#/components/responses/Unauthorized" /v1/merchant/store: get: summary: Get store operationId: getMerchantStore tags: [Store] responses: 200: description: Store information for the merchant content: application/json: schema: $ref: "#/components/schemas/Store" 401: $ref: "#/components/responses/Unauthorized" /v1/merchant/products: get: summary: List products operationId: listProducts tags: [Products] description: | Returns the merchant's product catalog with cursor-based pagination. Supports filtering by search (name/sku/gtin), brand, category, status, and price range (min_price/max_price columns). All price fields are returned as numbers (not strings). parameters: - in: query name: limit schema: type: integer default: 25 description: Number of results to return (max 100) - in: query name: cursor schema: type: string description: Cursor for pagination (from `next_page`) # v2.1.0 filters - in: query name: search schema: type: string minLength: 3 description: Search by name (LIKE), sku, or gtin (exact match) - in: query name: brand schema: type: string description: Filter by brand (exact match) - in: query name: category schema: type: string description: Filter by category (exact match) - in: query name: status schema: type: string enum: [active, inactive] description: Filter by product status - in: query name: price_min schema: type: number description: Filter products with min_price >= value - in: query name: price_max schema: type: number description: Filter products with max_price <= value - in: query name: sort schema: type: string enum: [name, sku, price, brand, category, status, created_at, updated_at] description: Sort field - in: query name: order schema: type: string enum: [asc, desc] default: asc description: Sort direction responses: 200: description: Paginated product list content: application/json: schema: type: object properties: results: type: array items: $ref: "#/components/schemas/Product" next_page: type: string nullable: true 401: $ref: "#/components/responses/Unauthorized" put: summary: Upsert products (bulk) operationId: bulkUpsertProducts tags: [Products] description: | Create or update products by SKU (max 50 per call). For an SKU that already exists this is a partial update: send only the fields you want to change — any field you omit is left unchanged. `name` and `price` are required only when creating a new SKU; once the product exists they are optional, but when supplied they cannot be null or empty. Note: Competitor Discovery is not triggered automatically when products are added or updated through the API. Launch it from your Pricefy dashboard when you want to find competitors for your catalog. requestBody: required: true content: application/json: schema: type: array maxItems: 50 items: $ref: '#/components/schemas/Product' responses: 201: description: Catalog updated successfully content: application/json: schema: $ref: "#/components/schemas/SuccessfulOperation" 400: description: Validation error, batch size exceeded, or read-only access content: application/json: schema: $ref: "#/components/schemas/Error" 401: $ref: "#/components/responses/Unauthorized" /v1/merchant/products/{sku}: parameters: - name: sku in: path required: true schema: type: string get: summary: Get product operationId: getProduct tags: [Products] responses: 200: description: Product details with monitored URLs content: application/json: schema: $ref: "#/components/schemas/Product" 401: $ref: "#/components/responses/Unauthorized" 404: $ref: "#/components/responses/NotFound" put: summary: Upsert product operationId: upsertProduct tags: [Products] description: | Create or update a single product by SKU. For an existing product this is a partial update: send only the fields you want to change — any field you omit is left unchanged. `name` and `price` are required only when creating the product; on update they are optional, but when supplied they cannot be null or empty. Note: Competitor Discovery is not triggered automatically when a product is added or updated through the API. Launch it from your Pricefy dashboard when you want to find competitors for your catalog. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/Product' responses: 201: description: Product upserted content: application/json: schema: $ref: "#/components/schemas/SuccessfulOperation" 400: description: Validation error content: application/json: schema: $ref: "#/components/schemas/Error" 401: $ref: "#/components/responses/Unauthorized" delete: summary: Delete product operationId: deleteProduct tags: [Products] responses: 200: description: Product deleted content: application/json: schema: $ref: "#/components/schemas/SuccessfulOperation" 401: $ref: "#/components/responses/Unauthorized" 404: $ref: "#/components/responses/NotFound" /v1/competitors: get: summary: List competitors operationId: listCompetitors tags: [Competitors] description: | Returns all competitors associated with the merchant, with aggregated price analysis. Each competitor includes name, logo, counts of monitored/lower/higher/equal products, and MAP infringements. Paginated (default 25 per page). parameters: - in: query name: page schema: type: integer default: 1 - in: query name: limit schema: type: integer default: 25 description: Results per page (max 100) # v2.1.0 filters - in: query name: search schema: type: string minLength: 3 description: Search by domain (LIKE) - in: query name: status schema: type: string enum: [active, disabled] description: Filter by competitor status - in: query name: sort schema: type: string enum: [domain, monitored_products, status] description: Sort field - in: query name: order schema: type: string enum: [asc, desc] default: asc description: Sort direction responses: 200: description: Paginated competitor list with price analysis content: application/json: schema: type: object properties: results: type: array items: $ref: "#/components/schemas/Competitor" next_page: type: string nullable: true 401: $ref: "#/components/responses/Unauthorized" post: summary: Add competitor operationId: addCompetitor tags: [Competitors] requestBody: content: application/json: schema: type: object required: [url] properties: url: type: string format: uri responses: 201: description: Competitor added content: application/json: schema: $ref: "#/components/schemas/SuccessfulOperation" 400: description: Invalid URL, not profiled, or limit exceeded content: application/json: schema: $ref: "#/components/schemas/Error" 401: $ref: "#/components/responses/Unauthorized" put: summary: Update competitor status operationId: updateCompetitorStatus tags: [Competitors] requestBody: required: true content: application/json: schema: type: object required: [url, status] properties: url: type: string format: uri status: type: string enum: [active, disabled] responses: 200: description: Status updated content: application/json: schema: $ref: "#/components/schemas/SuccessfulOperation" 400: description: Invalid status or limit exceeded content: application/json: schema: $ref: "#/components/schemas/Error" 401: $ref: "#/components/responses/Unauthorized" 404: $ref: "#/components/responses/NotFound" /v1/competitors/{domain}: parameters: - name: domain in: path required: true schema: type: string description: "Competitor domain (e.g. `amazon.it`, `ebay.com`)" example: "amazon.it" get: summary: Get competitor operationId: getCompetitor tags: [Competitors] description: Get details for a specific competitor by domain name, including price analysis stats. responses: 200: description: Competitor details with price analysis content: application/json: schema: $ref: "#/components/schemas/Competitor" 401: $ref: "#/components/responses/Unauthorized" 404: $ref: "#/components/responses/NotFound" /v1/competitors/urls: get: summary: List monitored URLs operationId: listMonitoredUrls tags: [Monitored URLs] description: | Returns competitor product URLs being monitored, with price comparison data. Includes full merchant product data (cost, min/max price, MAP, brand, category, stock, image, status) and competitor data (price, domain, logo, stock, currency). Supports advanced filtering by price position, stock, MAP infringement, and more. parameters: - in: query name: limit schema: type: integer default: 25 description: Results per page (max 100) - in: query name: page schema: type: integer default: 1 - in: query name: competitor_id schema: type: integer - in: query name: sku schema: type: string - in: query name: url schema: type: string - in: query name: last_analyzed_at schema: type: string format: date-time # v2.1.0 filters - in: query name: search schema: type: string minLength: 3 description: Search by SKU, product name, or competitor URL - in: query name: brand schema: type: string description: Filter by product brand - in: query name: status schema: type: string enum: [enabled, disabled, in_progress, scraping_failed, not_found, missing_price] description: Filter by URL monitoring status - in: query name: diff schema: type: string enum: [lower, higher, equal] description: "Price position: lower = merchant cheaper, higher = merchant more expensive" - in: query name: stock schema: type: string enum: [in_stock, out_of_stock] description: Filter by competitor stock - in: query name: map_infringement schema: type: string enum: ["0", "1"] description: "1 = competitor price below MAP" - in: query name: sort schema: type: string enum: [competitor_domain, competitor_price, product_price, price_diff, percentage_diff, status, analyzed_at] - in: query name: order schema: type: string enum: [asc, desc] default: asc responses: 200: description: Paginated monitored URLs content: application/json: schema: type: object properties: results: type: array items: $ref: "#/components/schemas/CompetitorUrl" next_page: type: string nullable: true 401: $ref: "#/components/responses/Unauthorized" put: summary: Upsert monitored URLs operationId: upsertMonitoredUrls tags: [Monitored URLs] requestBody: required: true content: application/json: schema: type: array maxItems: 50 items: type: object required: [merchant_product_sku, competitor_url, status] properties: merchant_product_sku: type: string competitor_url: type: string format: uri status: type: string enum: [active, disabled] price_adjuster_rule: type: object description: >- Optional. Adjusts the competitor's scraped price before it is compared with yours (for example to add local tax or shipping). When enabled, the scraped price is recalculated using the chosen operator and value. required: [enabled] properties: enabled: type: boolean description: Turn the adjustment on or off while keeping its configuration. operator: type: string enum: [multiply, divide, add, subtract, percentage_add, percentage_subtract, add_vat, subtract_vat] description: >- How the value is applied. Use add_vat to add VAT at the given rate to the scraped price, or subtract_vat to remove VAT and recover the net price. Required when enabled is true. value: type: number description: >- The amount applied with the operator (for add_vat and subtract_vat it is the VAT rate as a percentage). Must be greater than 0 (and below 100 for percentage_subtract). Required when enabled is true. description: type: string maxLength: 500 description: >- Optional note describing the adjustment (for example "Pack of 6 — competitor sells single units"). responses: 200: description: URLs updated content: application/json: schema: $ref: "#/components/schemas/SuccessfulOperation" 400: description: Validation error content: application/json: schema: $ref: "#/components/schemas/Error" 401: $ref: "#/components/responses/Unauthorized" 402: description: Monitored URLs limit exceeded (error_code 109) content: application/json: schema: $ref: "#/components/schemas/LimitExceededError" delete: summary: Delete monitored URLs operationId: deleteMonitoredUrls tags: [Monitored URLs] requestBody: content: application/json: schema: type: array maxItems: 50 items: type: object properties: competitor_id: type: integer merchant_product_sku: type: string responses: 200: description: URLs deleted content: application/json: schema: $ref: "#/components/schemas/SuccessfulOperation" 400: description: Batch size exceeded content: application/json: schema: $ref: "#/components/schemas/Error" 401: $ref: "#/components/responses/Unauthorized" # v3.5.0 — price-history detail for one monitored URL (a SKU at one competitor) /v1/competitors/urls/detail: get: summary: Monitored URL price-history detail operationId: getMonitoredUrlDetail tags: [Monitored URLs] description: | Price-history detail for a single monitored URL: one of your SKUs at one competitor. Returns the competitor's daily price series over the requested window (with your own price for each day), summary statistics (low/high/average and the number of points) and the current price with its delta versus your price. Powers the price chart on the product detail. parameters: - in: query name: sku required: true schema: type: string description: Your product SKU. - in: query name: competitor_id required: true schema: type: integer description: The competitor the monitored URL belongs to. - in: query name: days schema: type: integer default: 30 minimum: 1 maximum: 90 description: Size of the trailing window in days, ending today. responses: 200: description: Price-history detail content: application/json: schema: $ref: "#/components/schemas/MonitoredUrlDetail" 400: description: Missing or invalid sku / competitor_id content: application/json: schema: $ref: "#/components/schemas/Error" 401: $ref: "#/components/responses/Unauthorized" 404: $ref: "#/components/responses/NotFound" /v1/map-infringements: get: summary: List MAP infringements operationId: listMapInfringements tags: [MAP Infringements] description: | Resellers selling below your Minimum Advertised Price. By default returns the competitors that went below MAP in the last 7 days. parameters: - in: query name: page schema: type: integer default: 1 - in: query name: limit schema: type: integer default: 25 - in: query name: direction schema: type: string enum: [went_infringed, went_respected, all] default: went_infringed description: Infringements (went_infringed), back-in-compliance (went_respected) or both (all) - in: query name: competitor_id schema: type: integer description: Filter by competitor - in: query name: period schema: type: integer default: 7 description: Look-back window in days - in: query name: min_gap_pct schema: type: number description: Only rows whose absolute gap from MAP is at least this percentage - in: query name: search schema: type: string minLength: 3 description: Search by product SKU, product name or competitor domain responses: 200: description: Paginated MAP infringements content: application/json: schema: type: object properties: results: type: array items: $ref: "#/components/schemas/MapInfringement" next_page: type: string nullable: true 401: $ref: "#/components/responses/Unauthorized" /v1/map-infringement-rules: get: summary: List MAP infringement rules operationId: listMapInfringementRules tags: [MAP Infringements] description: | Returns the Minimum Advertised Price rules configured by the merchant. Each rule watches a set of competitors and flags resellers selling below MAP. Active rules are listed first. parameters: - in: query name: page schema: type: integer default: 1 - in: query name: limit schema: type: integer default: 25 - in: query name: search schema: type: string minLength: 3 description: Search by rule name - in: query name: status schema: type: string enum: [active, disabled] responses: 200: description: Paginated MAP infringement rules content: application/json: schema: type: object properties: results: type: array items: $ref: "#/components/schemas/MapInfringementRule" next_page: type: string nullable: true 401: $ref: "#/components/responses/Unauthorized" /v1/dynamic-pricing/list: get: summary: List repricing rules operationId: listRepricingRules tags: [Repricing] responses: 200: description: Repricing rules content: application/json: schema: type: object properties: results: type: array items: $ref: "#/components/schemas/RepricingRule" 401: $ref: "#/components/responses/Unauthorized" # v2.1.0 — New endpoints /v1/dynamic-pricing/preview: get: summary: Repricing preview operationId: getRepricingPreview tags: [Repricing] description: | Returns repricing results from the latest job execution of each rule. Shows suggested, applied, skipped, and errored price changes with full margin calculations. Results include error details from both the job and the apply process. parameters: - in: query name: page schema: type: integer default: 1 - in: query name: limit schema: type: integer default: 25 - in: query name: rule_id schema: type: integer description: Filter by repricing rule - in: query name: search schema: type: string minLength: 3 description: Search by SKU, product name, or rule name - in: query name: status schema: type: string enum: [suggested, skipped, repriced, error] description: Filter by result status - in: query name: diff schema: type: string enum: [lower, higher, equal] description: Price position vs competitor responses: 200: description: Paginated repricing preview results content: application/json: schema: type: object properties: results: type: array items: $ref: "#/components/schemas/RepricingPreviewResult" next_page: type: string nullable: true 401: $ref: "#/components/responses/Unauthorized" # v3.10.0 — Apply suggested repricing prices /v1/dynamic-pricing/apply/{rule_id}: post: summary: Apply suggested prices operationId: applyRepricing tags: [Repricing] description: | Apply the suggested price to selected products (SKUs) of one repricing rule, in bulk (up to 30 SKUs per call). Take the SKUs from the suggested results of the repricing preview. This queues the price change: the response confirms the request was accepted, and the final result is polled from the repricing preview (each product moves from "suggested" to "repriced" or "error"). SKUs that are no longer suggested are reported back as skipped. To apply across multiple rules or more than 30 SKUs, send multiple requests. parameters: - in: path name: rule_id required: true schema: type: integer description: The repricing rule id. requestBody: required: true content: application/json: schema: type: object required: [skus] properties: skus: type: array minItems: 1 maxItems: 30 description: Up to 30 products to apply, taken from the suggested preview results. items: type: object required: [sku] properties: sku: type: string description: The product SKU. example: skus: - sku: "ABC-1" - sku: "ABC-2" responses: 202: description: The repricing apply was accepted and queued. content: application/json: schema: type: object properties: status: type: string example: success message: type: string example: Repricing apply queued. data: type: object properties: rule_id: type: integer queued_skus: type: array items: type: string skipped_skus: type: array items: type: object properties: sku: type: string reason: type: string example: not_suggested 400: description: Invalid request, or none of the provided SKUs are currently suggested for this rule. 402: description: Repricing apply limit reached for the current plan. 404: description: Repricing rule not found. 409: description: An apply is already running for this rule. 422: description: Repricing is not available for this store platform. 401: $ref: "#/components/responses/Unauthorized" /v1/reports: get: summary: List reports operationId: listReports tags: [Reports] description: | Returns scheduled reports (catalog exports, competitor exports, etc.). Includes computed `next_run_at` based on frequency and daily_time configuration. Filter by status (SCHEDULED/RUNNING/COMPLETE/FAILED), frequency, or enabled flag. parameters: - in: query name: page schema: type: integer default: 1 - in: query name: limit schema: type: integer default: 25 - in: query name: status schema: type: string enum: [scheduled, running, complete, failed] - in: query name: frequency schema: type: string enum: [hourly, daily, weekly] - in: query name: enabled schema: type: string enum: ["0", "1"] responses: 200: description: Paginated report list content: application/json: schema: type: object properties: results: type: array items: $ref: "#/components/schemas/Report" next_page: type: string nullable: true 401: $ref: "#/components/responses/Unauthorized" /v1/reports/{id}: parameters: - name: id in: path required: true schema: type: integer get: summary: Get report operationId: getReport tags: [Reports] responses: 200: description: Report detail content: application/json: schema: $ref: "#/components/schemas/ReportDetail" 401: $ref: "#/components/responses/Unauthorized" 404: $ref: "#/components/responses/NotFound" /v1/alert-rules: get: summary: List alert rules operationId: listAlertRules tags: [Alerts] description: | Returns alert rules configured by the merchant. Each rule defines conditions (price/stock changes) that trigger notifications. Includes competitor count, last notification date, and total alerts triggered. parameters: - in: query name: page schema: type: integer default: 1 - in: query name: limit schema: type: integer default: 25 - in: query name: search schema: type: string minLength: 3 description: Search by rule name - in: query name: status schema: type: string enum: [active, disabled] responses: 200: description: Paginated alert rules content: application/json: schema: type: object properties: results: type: array items: $ref: "#/components/schemas/AlertRule" next_page: type: string nullable: true 401: $ref: "#/components/responses/Unauthorized" /v1/alert-rules/{id}: parameters: - name: id in: path required: true schema: type: integer get: summary: Get alert rule operationId: getAlertRule tags: [Alerts] responses: 200: description: Alert rule detail with competitor list content: application/json: schema: $ref: "#/components/schemas/AlertRuleDetail" 401: $ref: "#/components/responses/Unauthorized" 404: $ref: "#/components/responses/NotFound" /v1/alert-rules/{id}/alerts: parameters: - name: id in: path required: true schema: type: integer get: summary: Get alert rule alerts operationId: getAlertRuleAlerts tags: [Alerts] description: Returns alerts triggered by this rule from DynamoDB parameters: - in: query name: last_sku schema: type: string description: Cursor for pagination (last SKU from previous page) - in: query name: instant schema: type: string enum: ["0", "1"] default: "0" description: Show instant alerts (prefix INSTANT- in DynamoDB) responses: 200: description: Alert results grouped by SKU content: application/json: schema: type: object properties: items: type: object description: | Alerts grouped by product SKU. Each key is a SKU string, value is an object: - `product_code`: string (nullable) - `product_stock`: integer (nullable) - `rule_name`: string — name of the alert rule - `rule_alert_type`: string — rule key (e.g. "price", "stock") - `child`: array of alert objects, each containing competitor_name, competitor_logo, competitor_url, price_change, price_change_percentage, price_change_fixed, merchant_variation_price, merchant_variation_previous_price, merchant_variation_stock, merchant_variation_previous_stock, variation_change_date additionalProperties: type: object properties: product_code: type: string nullable: true product_stock: type: integer nullable: true rule_name: type: string rule_alert_type: type: string child: type: array items: type: object page_size: type: integer first: type: string nullable: true last: type: string nullable: true 401: $ref: "#/components/responses/Unauthorized" 404: $ref: "#/components/responses/NotFound" /v1/alerts: get: summary: List alert variations operationId: listAlerts tags: [Alerts] description: Price/stock variations from competitors (last 7 days) parameters: - in: query name: page schema: type: integer default: 1 - in: query name: limit schema: type: integer default: 25 - in: query name: competitor_id schema: type: integer description: Filter by competitor responses: 200: description: Paginated alert variations with product/competitor enrichment content: application/json: schema: type: object properties: results: type: array items: $ref: "#/components/schemas/AlertVariation" next_page: type: string nullable: true 401: $ref: "#/components/responses/Unauthorized" /postman/collection.json: get: summary: Download the Postman collection operationId: downloadPostmanCollection tags: [Postman] description: | Returns the **complete Pricefy API as a Postman Collection v2.1** JSON file, mirroring [the public Pricefy Postman workspace](https://www.postman.com/pricefy/workspace/pricefy-api). Two ways to use it: 1. **Open the workspace online** — click [![Run in Postman](https://run.pstmn.io/button.svg)](https://www.postman.com/pricefy/workspace/pricefy-api) to land in the live workspace and fork it into your own. 2. **Download this JSON** and import it manually (`File → Import → Upload Files` in Postman, or `newman run pricefy-api.postman_collection.json` for CI). Set the `X-Api-Key` variable in the environment and you're ready to send requests. The file is regenerated from `openapi.yaml` whenever a new version of the API is released. responses: 200: description: Postman Collection v2.1 JSON content: application/json: schema: type: object description: Postman Collection v2.1 schema (see https://schema.postman.com/collection/json/v2.1.0/draft-07/collection.json) 404: description: Collection file not deployed (should not happen in production) security: [] /mcp: post: summary: MCP server (Streamable HTTP JSON-RPC) operationId: mcpServer tags: [MCP] security: - ApiKey: [] - OAuth2: [mcp:use] description: | **Model Context Protocol** endpoint. Speaks JSON-RPC 2.0 over HTTP (Streamable HTTP transport, MCP spec 2025-11-25). **Two authentication options**: - `X-Api-Key: ` — same header as the REST API. Use this with Claude Desktop, Cursor, Codex, and any client that supports custom headers. - `Authorization: Bearer ` — OAuth, used by ChatGPT custom connectors. Set it up from the connector dialog: see the **MCP support** section on the main page for the step-by-step guide. Permissions are enforced on every tool call — an authorization granted as read-only can never invoke destructive tools, regardless of how it was issued. **Setup snippets**: see the introduction at the top of this page. **Available tools (25)** Read-only (18): `get_account`, `get_store`, `list_products`, `get_product`, `list_competitors`, `get_competitor`, `list_monitored_urls`, `get_monitored_url_detail`, `list_repricing_rules`, `get_repricing_preview`, `list_reports`, `get_report`, `list_alerts`, `list_alert_rules`, `get_alert_rule`, `get_alerts_for_rule`, `list_map_infringements`, `list_map_infringement_rules`. Write (5): `upsert_product`, `bulk_upsert_products`, `add_competitor`, `update_competitor_status`, `batch_upsert_monitored_urls`. Destructive (2, require client confirmation): `delete_product`, `batch_delete_monitored_urls`. **Discovery via JSON-RPC**: - `initialize` — handshake (returns the `MCP-Session-Id` header) - `tools/list` — full tool catalog with input schemas - `tools/call` — invoke a tool by name with arguments requestBody: required: true content: application/json: schema: type: object description: JSON-RPC 2.0 envelope properties: jsonrpc: type: string example: "2.0" id: type: integer example: 1 method: type: string description: One of `initialize`, `tools/list`, `tools/call` example: "tools/list" params: type: object examples: initialize: summary: Handshake value: jsonrpc: "2.0" id: 1 method: "initialize" params: protocolVersion: "2025-06-18" capabilities: {} clientInfo: name: "curl" version: "1" listTools: summary: List available tools value: jsonrpc: "2.0" id: 2 method: "tools/list" callListProducts: summary: Invoke list_products value: jsonrpc: "2.0" id: 3 method: "tools/call" params: name: "list_products" arguments: limit: 10 sort: "price" order: "desc" parameters: - in: header name: Accept required: true schema: type: string enum: ["application/json, text/event-stream"] - in: header name: MCP-Session-Id required: false schema: type: string description: Returned by `initialize`, required on every subsequent call. responses: 200: description: JSON-RPC response content: application/json: schema: type: object properties: jsonrpc: type: string example: "2.0" id: type: integer result: type: object 401: $ref: "#/components/responses/Unauthorized" 403: description: Forbidden — the API key does not have permission for the invoked tool's group+method components: responses: Unauthorized: description: Unauthorized — missing or invalid API key content: application/json: schema: $ref: "#/components/schemas/Error" NotFound: description: Resource not found content: application/json: schema: $ref: "#/components/schemas/Error" schemas: Account: type: object properties: account_type: type: string enum: [MERCHANT, BRAND] description: Drives the app's mode — BRAND switches dashboard, Competitors→Resellers and Movers→MAP. subscription_type: type: string description: Plan code (e.g. "free", "business") subscription_name: type: string description: Human-readable plan name (e.g. "Business") subscription_status: type: string description: One of active, trialing, past_due, unpaid, inactive subscription_started_at: type: string format: date-time products_limit: type: integer description: Effective product import limit (plan + override + additional) competitors_nominal_limit: type: string nullable: true competitors_limit: type: integer description: Effective competitor limit (plan + override) # v2.3.0 — Effective plan limits vector plan_limits: type: object description: | Effective plan limits with override, addon and additional_* applied. Single source of truth for what the merchant is actually allowed to do. properties: import_limit_product: type: integer competitor_limit: type: integer max_monitored_urls: type: integer limit_automatch: type: integer edit_additional_email_for_alerts: type: boolean limit_additional_email_for_alerts: type: integer rate_limit: type: integer description: API rate limit (requests/min) has_override: type: boolean description: True if max_monitored_urls comes from billing_profile_override base_monitored_urls: type: integer description: Plan/override base before addon stack addon_monitored_urls: type: integer description: Active paid addon contribution addon_quantity: type: integer merchant: type: object properties: name: { type: string, nullable: true } surname: { type: string, nullable: true } company_name: { type: string, nullable: true } email: { type: string, nullable: true } currency_code: { type: string, nullable: true } usage: type: object description: Current usage vs limits, mirroring the web /account/usage page. properties: products: { type: integer } competitors: { type: integer } monitored_urls: { type: integer } automatch_requests: { type: integer } automatch_limit: { type: integer, nullable: true } single_discovery_used: { type: integer } single_discovery_daily_limit: { type: integer } Store: type: object properties: platform: type: string nullable: true description: Raw platform code (e.g. shopify, woocommerce, external_data_feed); null if none. platform_label: type: string nullable: true description: Display label (Shopify, WooCommerce, CSV, Google Shopping…); null if no feed. platform_icon: type: string nullable: true description: Stable icon slug for the platform logo (shopify, woocommerce, magento, prestashop, bigcommerce, google, csv…); null when no known logo. store_url: type: string nullable: true feed_connected: type: boolean description: Whether a product feed has completed an import. added_at: type: string format: date-time nullable: true last_import: type: string format: date-time nullable: true last_imported_products: type: integer Product: type: object description: | Product from the merchant's catalog. - When **reading** (GET), `status` is returned as `active` or `inactive`. - When **writing** (PUT upsert), `status` accepts `active` or `disabled`. - Numeric fields (`cost`, `price`, `min_price`, `max_price`, `map`) must be sent as numbers using a dot as the decimal separator, e.g. `1079.50` — a comma (`1079,50`) or any non-numeric value is rejected with a 400 validation error. - `GET /v1/merchant/products/{sku}` includes an additional `monitored_urls` array. properties: id: type: integer sku: type: string name: type: string brand: type: string category: type: string code: type: string description: GTIN/barcode picture_url: type: string product_url: type: string description: URL of the product page on the merchant store cost: type: number price: type: number min_price: type: number max_price: type: number map: type: number description: Minimum Advertised Price status: type: string description: "GET returns `active`/`inactive`. PUT accepts `active`/`disabled`." count_competitor_urls: type: integer description: "Number of monitored competitor URLs for this product (only in list endpoint)" count_suggested_urls: type: integer description: "Number of pending automatch URL suggestions (only in list endpoint)" tags: type: array description: "Tag names assigned to the product (empty array when the product has no tags)." items: type: string additional_fields: type: object writeOnly: true description: > Optional map of extra fields from your source platform (key → value) kept alongside the product. Send it on a PUT upsert to store or update those values; set a value to null or an empty string to remove that key. Values are stored as text (numbers and true/false are accepted and converted). Write-only: not returned in product GET responses. additionalProperties: type: string monitored_urls: type: array description: "Only returned in GET /v1/merchant/products/{sku} (product detail)" items: type: object properties: id: type: integer competitor_url: type: string price: type: number status: type: string enum: [Disabled, Enabled, In Progress, Scraping Failed, Not Found, Missing Price] error_status_code: type: string scheduled_at: type: string format: date-time analyzed_at: type: string format: date-time title: type: string competitor_id: type: integer qty: type: integer brand: type: string picture_url: type: string code: type: string RepricingRule: type: object properties: id: type: integer name: type: string automatic: type: string enum: [automatic, semi-automatic] status: type: string enum: [Active, Disabled] all_competitors: type: integer enum: [0, 1] description: 1 = the rule applies to all competitors (per-rule count is 0) competitors: type: integer job_status: type: string last_runned: type: string format: date-time nullable: true created_at: type: string format: date-time updated_at: type: string format: date-time # v2.1.0 RepricingPreviewResult: type: object properties: result_id: type: integer sku: type: string product_name: type: string product_image: type: string product_url: type: string product_code: type: string rule_id: type: integer rule_name: type: string rule_json: type: string description: JSON rule configuration merchant_price: type: number merchant_cost: type: number competitor_price: type: number repriced_price: type: number adjusted_repriced_price: type: number highest_competitor_price: type: number highest_competitor_id: type: integer cheapest_competitor_price: type: number cheapest_competitor_id: type: integer avg_competitor_price: type: number merchant_min_price: type: number merchant_max_price: type: number status: type: integer description: "Result status: 1=suggested, 2=processing, 3=applied, 4=rejected, 5=skipped" status_code: type: string nullable: true description: Machine-readable status code (e.g. BELOW_MIN_PRICE, ABOVE_MAX_PRICE) applied_status: type: integer description: "Apply status: 0=not applied, 1=repriced (applied successfully), 2=pending, 3=error" applied_at: type: string format: date-time nullable: true merchant_gross_margin: type: number merchant_gross_margin_perc: type: number error_message: type: string nullable: true apply_error_info: type: string nullable: true result_updated_at: type: string format: date-time Competitor: type: object properties: id: type: integer domain: type: string description: Competitor domain (e.g. amazon.it) competitor_name: type: string description: Display name (falls back to domain if name is null) logo: type: string nullable: true description: URL of competitor logo status: type: integer enum: [0, 1] description: Per-merchant tracking switch. 1 = enabled, 0 = disabled (disabled takes priority over `ready_to_analyze` when labelling). ready_to_analyze: type: integer enum: [0, 1, 2, 3] description: Profiling state when enabled. 1 = active, 0 = needs profile update, 2 = suspended, 3 = profiling in progress. monitored_products: type: integer description: Number of monitored product URLs for this competitor lower_products: type: integer description: Products where merchant price is lower than competitor higher_products: type: integer description: Products where merchant price is higher than competitor equal_products: type: integer description: Products where prices are equal map_infringements: type: integer description: Products where competitor price is below MAP (Minimum Advertised Price) count_suggested_urls: type: integer description: Number of pending URL suggestions from automatch (not yet approved) price_adjuster: type: object description: >- General price adjustment configured for this competitor. It applies to every monitored URL of the competitor and recalculates its prices before they are compared with yours (a per-URL rule, when set, is applied on top of it). properties: enabled: type: boolean description: True when the general price adjustment is active (turned on and with a non-zero value). mode: type: string nullable: true enum: [plus, minus, divided, multiplied, add_vat, subtract_vat] description: The operation applied to the competitor price. value: type: number nullable: true description: The adjustment amount; the mode decides how it is applied. type: type: string nullable: true enum: [percentage, fixed] description: Whether the value is a percentage or a fixed amount (VAT modes are always percentage). CompetitorUrl: type: object properties: id: type: integer competitor_id: type: integer competitor_domain: type: string competitor_logo: type: string nullable: true competitor_product_title: type: string description: Title of the competitor product page competitor_product_image: type: string description: Image URL from competitor product page competitor_product_code: type: string description: GTIN/barcode from competitor competitor_brand: type: string description: Brand from competitor product page competitor_price: type: number description: Competitor product price product_price: type: number description: Merchant's own product price price_diff: type: number nullable: true percentage_diff: type: number nullable: true map_infringement: type: integer enum: [0, 1] currency_code: type: string nullable: true status: type: string enum: [Disabled, Enabled, In Progress, Scraping Failed, Not Found, Missing Price] error_status_code: type: string competitor_url: type: string variant_list: type: array nullable: true description: Variant data extracted from competitor product (sizes, colors, etc.) items: type: object price_adjuster_rule: type: object nullable: true description: >- Optional per-URL price scaling applied to the competitor's scraped price before it is compared with yours. Null when no rule is configured. properties: enabled: type: boolean operator: type: string enum: [multiply, divide, add, subtract, percentage_add, percentage_subtract, add_vat, subtract_vat] value: type: number nullable: true description: type: string nullable: true has_price_adjustment: type: integer enum: [0, 1] description: >- 1 when a general, account-wide price adjustment is active for this competitor, so the competitor prices shown here are already recalculated with it. This general adjustment applies first; the optional per-URL price_adjuster_rule is applied on top. 0 when no general adjustment is active. competitor_stock: type: integer nullable: true description: Stock quantity from competitor merchant_product_sku: type: string merchant_product_code: type: string merchant_product_url: type: string merchant_product_title: type: string # v2.1.0 A4 columns product_cost: type: number nullable: true product_min_price: type: number nullable: true product_max_price: type: number nullable: true product_map: type: number nullable: true product_brand: type: string nullable: true product_category: type: string nullable: true product_stock: type: integer nullable: true product_image: type: string nullable: true product_status: type: string enum: [active, inactive] analyzed_at: type: string format: date-time scheduled_at: type: string format: date-time created_at: type: string format: date-time updated_at: type: string format: date-time # v3.5.0 MonitoredUrlDetail: type: object properties: product: type: object properties: sku: type: string title: type: string nullable: true brand: type: string nullable: true code: type: string nullable: true description: GTIN/barcode. image_url: type: string nullable: true competitor: type: object properties: id: type: integer domain: type: string logo: type: string nullable: true url: type: string description: The monitored competitor product URL. currency_code: type: string description: ISO currency code of the prices (defaults to EUR). range: type: object properties: date_start: type: string format: date date_end: type: string format: date days: type: integer current: type: object properties: competitor_price: type: number nullable: true my_price: type: number nullable: true diff: type: number nullable: true description: my_price − competitor_price. diff_percentage: type: number nullable: true stats: type: object description: Computed over the competitor price points in the window. properties: low: type: number nullable: true high: type: number nullable: true average: type: number nullable: true changes: type: integer description: Number of days that have a competitor price. series: type: array description: One entry per day with a competitor price, oldest first. items: type: object properties: date: type: string format: date competitor_price: type: number my_price: type: number nullable: true description: Your price that day (last-known carried forward). # v2.1.0 Report: type: object properties: id: type: integer name: type: string internal_id: type: string frequency: type: string enum: [DAILY, WEEKLY, HOURLY] enabled: type: integer status: type: string enum: [SCHEDULED, RUNNING, COMPLETE, FAILED] report_type: type: string description: Report type identifier (filter_url) created_by: type: integer format: type: string enum: [csv, xlsx, pdf] next_run_at: type: string format: date-time nullable: true scheduled_at: type: string format: date-time nullable: true started_at: type: string format: date-time nullable: true finished_at: type: string format: date-time nullable: true created_at: type: string format: date-time updated_at: type: string format: date-time ReportDetail: allOf: - $ref: "#/components/schemas/Report" - type: object properties: report_params: type: object description: Report parameters (format, daily_time, communications) filter_params: type: object nullable: true description: Filters applied to this report AlertRule: type: object properties: rule_id: type: integer rule_name: type: string rules: type: object description: Alert rule configuration rule_status: type: integer rule_notifications: type: object alert_type: type: string enum: [INSTANT, DAILY, ALL] all_competitors: type: integer enum: [0, 1] latest_total_alerts: type: integer competitors: type: integer description: Number of associated competitors last_notified_at: type: string format: date-time nullable: true updated_at: type: string format: date-time created_at: type: string format: date-time AlertRuleDetail: allOf: - $ref: "#/components/schemas/AlertRule" - type: object properties: competitor_list: type: array items: type: object properties: id: type: integer domain: type: string logo: type: string nullable: true MapInfringement: type: object description: A reseller selling below (or back above) your Minimum Advertised Price. properties: id: type: integer product_sku: type: string product_name: type: string nullable: true product_image: type: string nullable: true product_code: type: string nullable: true competitor_id: type: integer competitor_domain: type: string nullable: true competitor_logo: type: string nullable: true competitor_url: type: string nullable: true map: type: number description: Your minimum advertised price competitor_price: type: number description: Competitor price after the change competitor_previous_price: type: number description: Competitor price before the change gap_pct: type: number description: Percentage gap from MAP (negative when below MAP) currency_code: type: string description: Merchant currency (ISO 4217) direction: type: string enum: [went_infringed, went_respected] detected_at: type: string format: date-time MapInfringementRule: type: object properties: rule_id: type: integer rule_name: type: string rules: type: object description: MAP rule configuration (direction, competitor filters, thresholds) rule_status: type: integer enum: [0, 1] description: 1 = active, 0 = disabled rule_notifications: type: object rule_type: type: string enum: [DAILY, WEEKLY, MONTHLY] all_competitors: type: integer enum: [0, 1] latest_total_alerts: type: integer job_status: type: string competitors: type: integer description: Number of associated competitors updated_at: type: string format: date-time created_at: type: string format: date-time AlertVariation: type: object description: A price or stock variation detected from a competitor (last 7 days) properties: id: type: integer competitor_id: type: integer competitor_url: type: string competitor_price: type: number description: Current competitor price after the variation competitor_previous_price: type: number description: Competitor price before the variation price_change: type: number description: Price difference (current - previous) competitor_stock: type: integer description: Current competitor stock after the variation competitor_previous_stock: type: integer description: Competitor stock before the variation variation_date: type: string format: date-time product_sku: type: string nullable: true product_name: type: string nullable: true product_image: type: string nullable: true product_price: type: number nullable: true description: Merchant's own product price (for context) competitor_domain: type: string nullable: true competitor_logo: type: string nullable: true SuccessfulOperation: type: object properties: status: type: string data: type: object nullable: true message: type: string Error: type: object properties: status: type: string data: type: object message: type: string LimitExceededError: type: object properties: status: type: string data: type: object properties: error_code: type: integer example: 109 message: type: string securitySchemes: ApiKey: type: apiKey in: header name: X-Api-Key OAuth2: type: oauth2 description: | Used by MCP clients that can't set a custom header, such as ChatGPT custom connectors. To set it up, follow the **Connect ChatGPT custom connector** guide on the main page — the AI client handles the entire sign-in / consent flow for you. flows: authorizationCode: authorizationUrl: https://api.pricefy.io/oauth/authorize tokenUrl: https://api.pricefy.io/oauth/token refreshUrl: https://api.pricefy.io/oauth/token scopes: mcp:use: Use the Pricefy MCP server (per-permission granularity chosen on the consent screen) security: - ApiKey: [] ```