{
  "openapi": "3.1.0",
  "info": {
    "title": "Dreamify Partner API",
    "version": "1.0.0",
    "summary": "Push partner listings (experiences, deals, products, courses, stays, talent, venues) into Dreamify destinations.",
    "description": "The Partner Network API lets outside partners (tour operators, deal sites, ticketing platforms, rental and hotel feeds) publish listings to Dreamify.\n\n**Environments.** Keys are `dpk_test_…` (sandbox, never public) or `dpk_live_…` (needs an active partner). Each key only sees its own environment.\n\n**Flow.** `PUT /v1/listings` (batch upsert by `external_id`) → schema validation (bad rows are rejected with readable errors) → auto-checks (media, price, category, city, duplicates) → `pending_review` or auto-approved → Dreamify ops approve → `published` (live) or `approved` (test). Webhooks tell you about approvals, rejections and expiry.\n\n**Taxonomy.** Three layers: main category → listing `type` (e.g. `host.tour`) → `destinations` (e.g. `experiences`, `deals`). `GET /v1/taxonomy` returns the tree, category slugs and cities.\n\n**Marketplace placement.** Set `market` to a DreamSuite Market taxonomy id (`GET /v1/taxonomy` → `market`) so the listing lands in the right Dreamify Marketplace group. Deals (anything sent to `deals` / `*.deals` with a `deal` block) show in the Marketplace with the \"On sale\" flag and the labels \"via <you>\" + \"Partner deal\".\n\n**Partner program.** Apply at https://developer.dreamify.com/partners/apply. Tiers (Standard, Preferred, Premier) unlock promotion surfaces, Sponsored placement and higher rate limits; see `GET /v1/me`.\n\nFull guide: PARTNER_API.md. Listing JSON Schema: /schema/listing.v1.schema.json."
  },
  "servers": [
    {
      "url": "https://dreamify-partner-api.netlify.app"
    }
  ],
  "security": [
    {
      "bearer": []
    }
  ],
  "tags": [
    {
      "name": "Account"
    },
    {
      "name": "Taxonomy"
    },
    {
      "name": "Listings"
    },
    {
      "name": "Promotion"
    },
    {
      "name": "Feeds"
    },
    {
      "name": "Sync runs"
    },
    {
      "name": "Webhooks"
    }
  ],
  "paths": {
    "/v1/me": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "Who am I",
        "description": "Partner, environment, key scopes and listing counts.",
        "responses": {
          "200": {
            "description": "Partner",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          },
          "422": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/taxonomy": {
      "get": {
        "tags": [
          "Taxonomy"
        ],
        "summary": "Listing types, destinations, category trees and cities",
        "security": [],
        "responses": {
          "200": {
            "description": "Taxonomy",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Taxonomy"
                }
              }
            }
          }
        }
      }
    },
    "/v1/listings:validate": {
      "post": {
        "tags": [
          "Listings"
        ],
        "summary": "Dry run: validate + auto-check without saving",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListingBatch"
              },
              "example": {
                "listings": [
                  {
                    "external_id": "sample-tour-001",
                    "type": "host.tour",
                    "destinations": [
                      "experiences",
                      "local.activities"
                    ],
                    "sample": true,
                    "title": "[Sample] Stanley Park bike tour",
                    "summary": "Sample listing for API testing: a 3-hour guided bike loop around the seawall with photo stops.",
                    "category": {
                      "cat": "sports"
                    },
                    "place": {
                      "city": "Vancouver",
                      "country": "CA"
                    },
                    "location": {
                      "name": "Seawall meeting point",
                      "address": "Denman St & W Georgia St, Vancouver, BC"
                    },
                    "media": [
                      {
                        "url": "https://images.unsplash.com/photo-1507035895480-2b3156c31fc8?w=1200",
                        "alt": "Bikes by the water"
                      }
                    ],
                    "price": {
                      "amount_cents": 6900,
                      "currency": "cad",
                      "unit": "per_person"
                    },
                    "sessions": [
                      {
                        "id": "s1",
                        "starts_at": "2026-10-28T17:00:00.000Z",
                        "ends_at": "2026-10-28T20:00:00.000Z",
                        "capacity": 12
                      },
                      {
                        "id": "s2",
                        "starts_at": "2026-11-04T17:00:00.000Z",
                        "ends_at": "2026-11-04T20:00:00.000Z",
                        "capacity": 12
                      }
                    ],
                    "timezone": "America/Vancouver",
                    "booking": {
                      "mode": "handoff",
                      "url": "https://example.com/sample/book/tour-001"
                    },
                    "experience": {
                      "duration_minutes": 180,
                      "included": [
                        "Bike",
                        "Helmet"
                      ],
                      "languages": [
                        "en"
                      ]
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Row results",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BatchResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          },
          "422": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/listings": {
      "put": {
        "tags": [
          "Listings"
        ],
        "summary": "Batch upsert by external_id (max 500)",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "description": "Creates or updates each listing. Rows that fail validation are not saved; the others are. 200 = all rows ok, 207 = some failed, 422 = all failed. Unchanged rows (same content) are skipped.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListingBatch"
              },
              "example": {
                "listings": [
                  {
                    "external_id": "sample-tour-001",
                    "type": "host.tour",
                    "destinations": [
                      "experiences",
                      "local.activities"
                    ],
                    "sample": true,
                    "title": "[Sample] Stanley Park bike tour",
                    "summary": "Sample listing for API testing: a 3-hour guided bike loop around the seawall with photo stops.",
                    "category": {
                      "cat": "sports"
                    },
                    "place": {
                      "city": "Vancouver",
                      "country": "CA"
                    },
                    "location": {
                      "name": "Seawall meeting point",
                      "address": "Denman St & W Georgia St, Vancouver, BC"
                    },
                    "media": [
                      {
                        "url": "https://images.unsplash.com/photo-1507035895480-2b3156c31fc8?w=1200",
                        "alt": "Bikes by the water"
                      }
                    ],
                    "price": {
                      "amount_cents": 6900,
                      "currency": "cad",
                      "unit": "per_person"
                    },
                    "sessions": [
                      {
                        "id": "s1",
                        "starts_at": "2026-10-28T17:00:00.000Z",
                        "ends_at": "2026-10-28T20:00:00.000Z",
                        "capacity": 12
                      },
                      {
                        "id": "s2",
                        "starts_at": "2026-11-04T17:00:00.000Z",
                        "ends_at": "2026-11-04T20:00:00.000Z",
                        "capacity": 12
                      }
                    ],
                    "timezone": "America/Vancouver",
                    "booking": {
                      "mode": "handoff",
                      "url": "https://example.com/sample/book/tour-001"
                    },
                    "experience": {
                      "duration_minutes": 180,
                      "included": [
                        "Bike",
                        "Helmet"
                      ],
                      "languages": [
                        "en"
                      ]
                    }
                  },
                  {
                    "external_id": "sample-deal-001",
                    "type": "host.activity",
                    "destinations": [
                      "deals",
                      "experiences"
                    ],
                    "sample": true,
                    "title": "[Sample] 40% off axe throwing for two",
                    "summary": "Sample listing for API testing: one-hour lane for two people with a coach, valid weekdays.",
                    "category": {
                      "cat": "games"
                    },
                    "place": {
                      "city": "Vancouver",
                      "country": "CA"
                    },
                    "media": [
                      {
                        "url": "https://images.unsplash.com/photo-1533560904424-a0c61dc306fc?w=1200"
                      }
                    ],
                    "price": {
                      "amount_cents": 3000,
                      "currency": "cad"
                    },
                    "booking": {
                      "url": "https://example.com/sample/deal-001"
                    },
                    "expires_at": "2026-12-21T02:00:00.000Z",
                    "experience": {
                      "schedule_mode": "flexible",
                      "duration_minutes": 60
                    },
                    "deal": {
                      "deal_category": "things-to-do",
                      "original_price_cents": 5000,
                      "deal_price_cents": 3000,
                      "fine_print": "Sample only. Not a real offer.",
                      "voucher_type": "voucher",
                      "redeem_by": "2027-01-20T02:00:00.000Z"
                    }
                  },
                  {
                    "external_id": "sample-stay-001",
                    "type": "travel.stay",
                    "destinations": [
                      "travel.stays"
                    ],
                    "sample": true,
                    "title": "[Sample] Kitsilano garden suite",
                    "summary": "Sample listing for API testing: one-bedroom garden suite near the beach, sleeps three.",
                    "category": {
                      "cat": "city-break"
                    },
                    "place": {
                      "city": "Vancouver",
                      "country": "CA"
                    },
                    "media": [
                      {
                        "url": "https://images.unsplash.com/photo-1505693416388-ac5ce068fe85?w=1200"
                      }
                    ],
                    "price": {
                      "amount_cents": 18500,
                      "currency": "cad",
                      "unit": "per_night"
                    },
                    "booking": {
                      "url": "https://example.com/sample/stay-001"
                    },
                    "stay": {
                      "property_type": "suite",
                      "bedrooms": 1,
                      "bathrooms": 1,
                      "max_guests": 3,
                      "amenities": [
                        "wifi",
                        "kitchen"
                      ],
                      "min_nights": 2,
                      "rate_unit": "night"
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "All rows saved",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BatchResult"
                }
              }
            }
          },
          "207": {
            "description": "Some rows failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BatchResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          },
          "422": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "get": {
        "tags": [
          "Listings"
        ],
        "summary": "List your listings",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Comma list: pending_review,approved,published,rejected,paused,expired,removed. Default: everything except removed."
          },
          {
            "name": "destination",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "type",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "city",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Title search"
          },
          {
            "name": "updated_since",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "maximum": 200
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "next_cursor from the previous page"
          }
        ],
        "responses": {
          "200": {
            "description": "Page",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/StoredListing"
                      }
                    },
                    "total": {
                      "type": "integer"
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          },
          "422": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/listings/{external_id}": {
      "get": {
        "tags": [
          "Listings"
        ],
        "summary": "Get one listing",
        "parameters": [
          {
            "name": "external_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Your external_id (URL-encode it)."
          }
        ],
        "responses": {
          "200": {
            "description": "Listing",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StoredListing"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          },
          "422": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "patch": {
        "tags": [
          "Listings"
        ],
        "summary": "Update with a JSON merge patch (RFC 7386)",
        "parameters": [
          {
            "name": "external_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Your external_id (URL-encode it)."
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              },
              "example": {
                "price": {
                  "amount_cents": 7900
                },
                "summary": "Now with a coffee stop."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          },
          "422": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "delete": {
        "tags": [
          "Listings"
        ],
        "summary": "Remove (soft delete; PUT again to restore)",
        "parameters": [
          {
            "name": "external_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Your external_id (URL-encode it)."
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Removed",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          },
          "422": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/listings/{external_id}:promote": {
      "post": {
        "tags": [
          "Promotion"
        ],
        "summary": "Request promotion across the network (reviewed by Dreamify)",
        "parameters": [
          {
            "name": "external_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Your external_id (URL-encode it)."
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "description": "Ask Dreamify to feature this listing on network surfaces: `marketplace`, `deals`, `explore`, `feed`. Allowed surfaces, Sponsored placement and the number of active promotions depend on your tier (GET /v1/me → partner.privileges). Every promotion is reviewed before it shows; approved promotions carry the label \"Partner deal\" (deals) and, when sponsored, \"Sponsored\". Status is on the listing: `promotion.status` requested → approved | rejected → ended.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "surfaces"
                ],
                "properties": {
                  "surfaces": {
                    "type": "array",
                    "items": {
                      "enum": [
                        "marketplace",
                        "deals",
                        "explore",
                        "feed"
                      ]
                    }
                  },
                  "sponsored": {
                    "type": "boolean"
                  },
                  "starts_at": {
                    "type": "string",
                    "format": "date-time"
                  },
                  "ends_at": {
                    "type": "string",
                    "format": "date-time"
                  }
                }
              },
              "example": {
                "surfaces": [
                  "deals",
                  "marketplace"
                ],
                "ends_at": "2026-12-31T23:59:00Z"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Requested",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          },
          "422": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "delete": {
        "tags": [
          "Promotion"
        ],
        "summary": "Withdraw / end a promotion",
        "parameters": [
          {
            "name": "external_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Your external_id (URL-encode it)."
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Ended",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          },
          "422": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/usage": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "Usage (last 30 days)",
        "description": "Listings by status, sync runs, webhook deliveries, API activity and this environment's keys (prefix and last use only).",
        "responses": {
          "200": {
            "description": "Usage",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          },
          "422": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/feeds": {
      "get": {
        "tags": [
          "Feeds"
        ],
        "summary": "List feeds",
        "responses": {
          "200": {
            "description": "Feeds",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          },
          "422": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "post": {
        "tags": [
          "Feeds"
        ],
        "summary": "Create a feed (JSON, CSV or XML + field mapping)",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FeedInput"
              },
              "example": {
                "name": "Tours CSV",
                "format": "csv",
                "url": "https://partner.example/feeds/tours.csv",
                "schedule": "daily",
                "mapping": {
                  "fields": {
                    "external_id": "id",
                    "title": "name",
                    "price.amount": "price",
                    "price.currency": "currency",
                    "media[0].url": "image",
                    "booking.url": "link",
                    "place.city": "city",
                    "category.cat": "category"
                  },
                  "defaults": {
                    "type": "host.tour",
                    "destinations": [
                      "experiences"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Feed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Feed"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          },
          "422": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/feeds:preview": {
      "post": {
        "tags": [
          "Feeds"
        ],
        "summary": "Preview a mapping on sample content (nothing saved)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "format"
                ],
                "properties": {
                  "format": {
                    "enum": [
                      "json",
                      "csv",
                      "xml"
                    ]
                  },
                  "url": {
                    "type": "string"
                  },
                  "content": {
                    "type": "string"
                  },
                  "mapping": {
                    "$ref": "#/components/schemas/FeedMapping"
                  },
                  "limit": {
                    "type": "integer"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Preview",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          },
          "422": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/feeds/{id}": {
      "get": {
        "tags": [
          "Feeds"
        ],
        "summary": "Get a feed",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Feed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Feed"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          },
          "422": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "patch": {
        "tags": [
          "Feeds"
        ],
        "summary": "Update a feed",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FeedInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Feed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Feed"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          },
          "422": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "delete": {
        "tags": [
          "Feeds"
        ],
        "summary": "Delete a feed (its listings stay)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          },
          "422": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/feeds/{id}:run": {
      "post": {
        "tags": [
          "Feeds"
        ],
        "summary": "Run a feed now",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "description": "Fetches the feed URL, or uses uploaded content: send the raw CSV/XML/JSON as the body (text/csv, application/xml) or `{\"content\": \"...\"}`.",
        "requestBody": {
          "required": false,
          "content": {
            "text/csv": {
              "schema": {
                "type": "string"
              }
            },
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "content": {}
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Run result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SyncRun"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          },
          "422": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/sync-runs": {
      "get": {
        "tags": [
          "Sync runs"
        ],
        "summary": "Recent sync runs (API batches and feed runs)",
        "parameters": [
          {
            "name": "feed_id",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "include",
            "in": "query",
            "schema": {
              "enum": [
                "errors"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Runs",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          },
          "422": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/sync-runs/{id}": {
      "get": {
        "tags": [
          "Sync runs"
        ],
        "summary": "One run with row errors",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Run",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SyncRun"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          },
          "422": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/webhooks": {
      "get": {
        "tags": [
          "Webhooks"
        ],
        "summary": "List webhooks",
        "responses": {
          "200": {
            "description": "Webhooks",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          },
          "422": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "post": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Register a webhook (secret shown once)",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "url"
                ],
                "properties": {
                  "url": {
                    "type": "string"
                  },
                  "events": {
                    "type": "array",
                    "items": {
                      "enum": [
                        "listing.approved",
                        "listing.rejected",
                        "listing.paused",
                        "listing.expired",
                        "listing.removed",
                        "*"
                      ]
                    }
                  }
                }
              },
              "example": {
                "url": "https://partner.example/hooks/dreamify",
                "events": [
                  "listing.approved",
                  "listing.rejected"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Webhook + secret",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          },
          "422": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/webhooks/{id}": {
      "delete": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Delete a webhook",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          },
          "422": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/webhooks/{id}:test": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Send a signed ping now",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Delivery result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          },
          "422": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/webhook-deliveries": {
      "get": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Recent deliveries",
        "responses": {
          "200": {
            "description": "Deliveries",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          },
          "422": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/events": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "Audit log for your partner account",
        "responses": {
          "200": {
            "description": "Events",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          },
          "422": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    }
  },
  "webhooks": {
    "listing.approved": {
      "post": {
        "summary": "A listing was approved (status published in live, approved in test)",
        "parameters": [
          {
            "name": "Dreamify-Event",
            "in": "header",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Dreamify-Delivery",
            "in": "header",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Dreamify-Signature",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "t=<unix>,v1=<hex HMAC-SHA256(secret, \"<t>.<raw body>\")>"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Return any 2xx within 10 s. Failures retry after 1, 5, 30, 120 and 720 minutes."
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearer": {
        "type": "http",
        "scheme": "bearer",
        "description": "Partner API key: dpk_test_… or dpk_live_…"
      }
    },
    "parameters": {
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "schema": {
          "type": "string",
          "maxLength": 200
        },
        "description": "Retry-safe writes: the same key + same request returns the stored response for 24 h (header Idempotent-Replayed: true). Same key + different request = 409."
      }
    },
    "responses": {
      "Error": {
        "description": "Error",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    },
    "schemas": {
      "Listing": {
        "title": "Dreamify partner listing v1",
        "type": "object",
        "required": [
          "external_id",
          "type",
          "title"
        ],
        "properties": {
          "external_id": {
            "type": "string",
            "maxLength": 200,
            "minLength": 1,
            "pattern": "^[\\w.:\\-/@#]+$",
            "description": "Your id for this listing. Unique per partner + environment; PUT with the same id updates it."
          },
          "type": {
            "type": "string",
            "enum": [
              "publish.image",
              "publish.article",
              "publish.news",
              "publish.video",
              "publish.podcast",
              "publish.music",
              "publish.profile",
              "local.profile",
              "local.deal",
              "local.item",
              "local.job",
              "local.menu",
              "local.service",
              "venues.profile",
              "local.ride",
              "local.activity",
              "travel.stay",
              "travel.package",
              "travel.retreat",
              "travel.adventure",
              "travel.car",
              "travel.cruise",
              "travel.deal",
              "host.event",
              "host.activity",
              "host.tour",
              "host.class",
              "host.retreat",
              "teach.course",
              "teach.workshop",
              "teach.cohort",
              "teach.coaching",
              "teach.webinar",
              "teach.instructor",
              "teach.membership",
              "sell.product",
              "sell.service",
              "sell.digital",
              "sell.subscription",
              "sell.gift-card",
              "sell.bundle",
              "talent.performer",
              "talent.creator",
              "talent.professional",
              "inspire.idea",
              "inspire.list",
              "inspire.challenge",
              "inspire.guide",
              "community.group",
              "community.club",
              "community.team"
            ],
            "description": "Listing type id from the shared DFB tree (category.type). See GET /v1/taxonomy."
          },
          "destinations": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "shop",
                "explore.images",
                "explore.articles",
                "explore.news",
                "explore.videos",
                "explore.podcasts",
                "explore.music",
                "explore.people",
                "local.places",
                "deals",
                "marketplace",
                "local.jobs",
                "local.meals",
                "local.services",
                "your-store",
                "local-venues",
                "local.rides",
                "local.activities",
                "travel.stays",
                "travel.packages",
                "travel.retreats",
                "travel.adventures",
                "travel.cars",
                "travel.cruises",
                "travel.deals",
                "travel.flights",
                "experiences",
                "learn",
                "learn.instructors",
                "local-talent",
                "ideas",
                "dream.lists",
                "dream.challenges",
                "community.groups",
                "feed",
                "cities"
              ]
            },
            "maxItems": 8,
            "uniqueItems": true,
            "description": "Where to publish. Must be allowed for the type; defaults to the type's first destination."
          },
          "title": {
            "type": "string",
            "maxLength": 200,
            "minLength": 3
          },
          "summary": {
            "type": "string",
            "maxLength": 500
          },
          "description": {
            "type": "string",
            "maxLength": 20000,
            "description": "Plain text or Markdown."
          },
          "language": {
            "type": "string",
            "maxLength": 20,
            "description": "BCP 47, e.g. en, fr-CA."
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "maxItems": 30
          },
          "sample": {
            "type": "boolean",
            "description": "Mark test/sample content. Sample listings can never go live."
          },
          "market": {
            "type": "string",
            "pattern": "^[a-z0-9][a-z0-9.-]{0,119}$",
            "description": "DreamSuite Market taxonomy id (GET /v1/taxonomy → market), e.g. \"places.restaurants\". Decides where the listing shows in the Dreamify Marketplace."
          },
          "category": {
            "type": "object",
            "properties": {
              "cat": {
                "type": "string",
                "maxLength": 80
              },
              "sub": {
                "type": "string",
                "maxLength": 80
              },
              "kind": {
                "type": "string",
                "maxLength": 40,
                "description": "Experiences only: events | activities (derived from cat when omitted)."
              }
            },
            "description": "Slugs from the main category's tree (GET /v1/taxonomy → categories)."
          },
          "place": {
            "type": "object",
            "properties": {
              "city": {
                "type": "string",
                "maxLength": 120
              },
              "region": {
                "type": "string",
                "maxLength": 120
              },
              "country": {
                "type": "string",
                "maxLength": 2,
                "pattern": "^[A-Za-z]{2}$"
              },
              "place_id": {
                "type": "string",
                "maxLength": 200,
                "description": "Dreamify place id, e.g. na.ca.bc.vancouver"
              },
              "online": {
                "type": "boolean"
              }
            }
          },
          "location": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string",
                "maxLength": 200
              },
              "address": {
                "type": "string",
                "maxLength": 500
              },
              "postal_code": {
                "type": "string",
                "maxLength": 20
              },
              "lat": {
                "type": "number",
                "minimum": -90,
                "maximum": 90
              },
              "lng": {
                "type": "number",
                "minimum": -180,
                "maximum": 180
              }
            }
          },
          "media": {
            "type": "array",
            "maxItems": 30,
            "items": {
              "type": "object",
              "required": [
                "url"
              ],
              "properties": {
                "url": {
                  "type": "string",
                  "maxLength": 2000,
                  "format": "uri",
                  "pattern": "^https://"
                },
                "type": {
                  "enum": [
                    "image",
                    "video"
                  ]
                },
                "alt": {
                  "type": "string",
                  "maxLength": 300
                },
                "width": {
                  "type": "integer"
                },
                "height": {
                  "type": "integer"
                }
              }
            }
          },
          "price": {
            "type": "object",
            "properties": {
              "amount_cents": {
                "type": "integer",
                "minimum": 0,
                "description": "Money in minor units (cents). 2500 = 25.00."
              },
              "amount": {
                "type": "number",
                "minimum": 0,
                "description": "Alternative to amount_cents in major units (25.00)."
              },
              "currency": {
                "type": "string",
                "maxLength": 3,
                "pattern": "^[A-Za-z]{3}$",
                "description": "ISO 4217, e.g. usd, cad."
              },
              "unit": {
                "enum": [
                  "total",
                  "per_person",
                  "per_item",
                  "per_night",
                  "per_hour",
                  "per_day",
                  "per_week",
                  "per_month",
                  "per_session"
                ]
              },
              "from": {
                "type": "boolean",
                "description": "\"From $X\" pricing."
              },
              "free": {
                "type": "boolean"
              }
            }
          },
          "offers": {
            "type": "array",
            "maxItems": 50,
            "items": {
              "type": "object",
              "required": [
                "name"
              ],
              "properties": {
                "id": {
                  "type": "string",
                  "maxLength": 100
                },
                "name": {
                  "type": "string",
                  "maxLength": 200
                },
                "price_cents": {
                  "type": "integer",
                  "minimum": 0,
                  "description": "Money in minor units (cents). 2500 = 25.00."
                },
                "original_price_cents": {
                  "type": "integer",
                  "minimum": 0,
                  "description": "Money in minor units (cents). 2500 = 25.00."
                },
                "currency": {
                  "type": "string",
                  "maxLength": 3
                },
                "quantity": {
                  "type": "integer",
                  "minimum": 0
                },
                "valid_from": {
                  "type": "string",
                  "format": "date-time"
                },
                "valid_to": {
                  "type": "string",
                  "format": "date-time"
                }
              }
            }
          },
          "starts_at": {
            "type": "string",
            "format": "date-time"
          },
          "ends_at": {
            "type": "string",
            "format": "date-time"
          },
          "timezone": {
            "type": "string",
            "maxLength": 60,
            "description": "IANA, e.g. America/Vancouver."
          },
          "sessions": {
            "type": "array",
            "maxItems": 500,
            "items": {
              "type": "object",
              "required": [
                "starts_at"
              ],
              "properties": {
                "id": {
                  "type": "string",
                  "maxLength": 100
                },
                "starts_at": {
                  "type": "string",
                  "format": "date-time"
                },
                "ends_at": {
                  "type": "string",
                  "format": "date-time"
                },
                "capacity": {
                  "type": "integer",
                  "minimum": 0
                },
                "remaining": {
                  "type": "integer",
                  "minimum": 0
                },
                "price_cents": {
                  "type": "integer",
                  "minimum": 0,
                  "description": "Money in minor units (cents). 2500 = 25.00."
                }
              }
            }
          },
          "booking": {
            "type": "object",
            "properties": {
              "mode": {
                "enum": [
                  "handoff",
                  "native"
                ],
                "default": "handoff"
              },
              "url": {
                "type": "string",
                "maxLength": 2000,
                "format": "uri",
                "pattern": "^https://"
              },
              "phone": {
                "type": "string",
                "maxLength": 40
              }
            },
            "description": "handoff = Dreamify sends guests to booking.url (required for sell/teach/host/rent). native = book on Dreamify (needs partner enablement)."
          },
          "booking_url": {
            "type": "string",
            "maxLength": 2000,
            "description": "Shorthand for booking.url."
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "description": "Listing is hidden after this time."
          },
          "rating": {
            "type": "object",
            "properties": {
              "value": {
                "type": "number",
                "minimum": 0,
                "maximum": 5
              },
              "count": {
                "type": "integer",
                "minimum": 0
              }
            }
          },
          "experience": {
            "type": "object",
            "description": "host.* types",
            "properties": {
              "schedule_mode": {
                "enum": [
                  "single",
                  "multi",
                  "weekly",
                  "flexible"
                ]
              },
              "duration_minutes": {
                "type": "integer"
              },
              "highlights": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "maxItems": 50
              },
              "included": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "maxItems": 50
              },
              "excluded": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "maxItems": 50
              },
              "meeting_point": {
                "type": "string",
                "maxLength": 2000
              },
              "min_age": {
                "type": "integer"
              },
              "languages": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "maxItems": 50
              },
              "accessibility": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "maxItems": 50
              },
              "cancellation_policy": {
                "type": "string",
                "maxLength": 2000
              }
            }
          },
          "deal": {
            "type": "object",
            "description": "Required when destinations include \"deals\".",
            "properties": {
              "deal_category": {
                "type": "string",
                "maxLength": 80,
                "description": "Slug from categories.deals"
              },
              "original_price_cents": {
                "type": "integer",
                "minimum": 0,
                "description": "Money in minor units (cents). 2500 = 25.00."
              },
              "deal_price_cents": {
                "type": "integer",
                "minimum": 0,
                "description": "Money in minor units (cents). 2500 = 25.00."
              },
              "discount_percent": {
                "type": "number"
              },
              "fine_print": {
                "type": "string",
                "maxLength": 2000
              },
              "redeem_by": {
                "type": "string",
                "format": "date-time"
              },
              "voucher_type": {
                "enum": [
                  "voucher",
                  "promo_code",
                  "instant",
                  "booking"
                ]
              },
              "promo_code": {
                "type": "string",
                "maxLength": 100
              },
              "max_per_customer": {
                "type": "integer"
              },
              "quantity_available": {
                "type": "integer"
              }
            }
          },
          "product": {
            "type": "object",
            "description": "sell.* types",
            "properties": {
              "sku": {
                "type": "string",
                "maxLength": 100
              },
              "brand": {
                "type": "string",
                "maxLength": 120
              },
              "gtin": {
                "type": "string",
                "maxLength": 20
              },
              "condition": {
                "enum": [
                  "new",
                  "used",
                  "refurbished"
                ]
              },
              "availability": {
                "enum": [
                  "in_stock",
                  "out_of_stock",
                  "preorder",
                  "limited"
                ]
              },
              "digital": {
                "type": "boolean"
              },
              "shipping": {
                "type": "object",
                "properties": {
                  "regions": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "maxItems": 50
                  },
                  "price_cents": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Money in minor units (cents). 2500 = 25.00."
                  },
                  "days": {
                    "type": "integer"
                  }
                }
              },
              "variants": {
                "type": "array",
                "maxItems": 100,
                "items": {
                  "type": "object",
                  "required": [
                    "name"
                  ],
                  "properties": {
                    "sku": {
                      "type": "string",
                      "maxLength": 100
                    },
                    "name": {
                      "type": "string",
                      "maxLength": 200
                    },
                    "price_cents": {
                      "type": "integer",
                      "minimum": 0,
                      "description": "Money in minor units (cents). 2500 = 25.00."
                    }
                  }
                }
              }
            }
          },
          "course": {
            "type": "object",
            "description": "teach.* types",
            "properties": {
              "format": {
                "enum": [
                  "online",
                  "in_person",
                  "hybrid",
                  "self_paced"
                ]
              },
              "level": {
                "enum": [
                  "beginner",
                  "intermediate",
                  "advanced",
                  "all"
                ]
              },
              "duration_hours": {
                "type": "number"
              },
              "lessons_count": {
                "type": "integer"
              },
              "certificate": {
                "type": "boolean"
              },
              "instructor": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200
                  },
                  "bio": {
                    "type": "string",
                    "maxLength": 2000
                  }
                }
              },
              "prerequisites": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "maxItems": 50
              }
            }
          },
          "stay": {
            "type": "object",
            "description": "rent.* types",
            "properties": {
              "property_type": {
                "type": "string",
                "maxLength": 80
              },
              "bedrooms": {
                "type": "integer"
              },
              "bathrooms": {
                "type": "number"
              },
              "max_guests": {
                "type": "integer"
              },
              "amenities": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "maxItems": 50
              },
              "check_in": {
                "type": "string",
                "maxLength": 40
              },
              "check_out": {
                "type": "string",
                "maxLength": 40
              },
              "min_nights": {
                "type": "integer"
              },
              "rate_unit": {
                "enum": [
                  "hour",
                  "day",
                  "night",
                  "week",
                  "month"
                ]
              },
              "deposit_cents": {
                "type": "integer",
                "minimum": 0,
                "description": "Money in minor units (cents). 2500 = 25.00."
              }
            }
          },
          "profile": {
            "type": "object",
            "description": "talent.* and venues.* types",
            "properties": {
              "kind": {
                "enum": [
                  "talent",
                  "venue"
                ]
              },
              "headline": {
                "type": "string",
                "maxLength": 200
              },
              "capacity": {
                "type": "integer"
              },
              "rate_cents": {
                "type": "integer",
                "minimum": 0,
                "description": "Money in minor units (cents). 2500 = 25.00."
              },
              "rate_unit": {
                "enum": [
                  "hour",
                  "day",
                  "event",
                  "set",
                  "project"
                ]
              },
              "genres": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "maxItems": 50
              },
              "skills": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "maxItems": 50
              },
              "amenities": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "maxItems": 50
              },
              "portfolio_urls": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "maxItems": 20
              }
            }
          },
          "studio": {
            "type": "object",
            "description": "studio.* types (video, show, podcast, music, article)",
            "properties": {
              "duration_seconds": {
                "type": "integer"
              },
              "embed_url": {
                "type": "string",
                "maxLength": 2000,
                "format": "uri",
                "pattern": "^https://"
              },
              "season": {
                "type": "integer"
              },
              "episode": {
                "type": "integer"
              },
              "published_at": {
                "type": "string",
                "format": "date-time"
              }
            }
          }
        },
        "additionalProperties": true
      },
      "ListingBatch": {
        "type": "object",
        "required": [
          "listings"
        ],
        "properties": {
          "listings": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Listing"
            },
            "maxItems": 500
          }
        }
      },
      "RowError": {
        "type": "object",
        "properties": {
          "path": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "message": {
            "type": "string"
          }
        }
      },
      "RowResult": {
        "type": "object",
        "properties": {
          "index": {
            "type": "integer"
          },
          "external_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "result": {
            "enum": [
              "created",
              "updated",
              "unchanged",
              "failed",
              "valid"
            ]
          },
          "id": {
            "type": "string"
          },
          "status": {
            "enum": [
              "pending_review",
              "approved",
              "published",
              "rejected",
              "paused",
              "expired",
              "removed"
            ]
          },
          "errors": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RowError"
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RowError"
            }
          },
          "checks": {
            "type": "object",
            "properties": {
              "passed": {
                "type": "boolean"
              },
              "blocking": {
                "type": "integer"
              },
              "problems": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              }
            }
          }
        }
      },
      "BatchResult": {
        "type": "object",
        "properties": {
          "sync_run_id": {
            "type": "string"
          },
          "environment": {
            "type": "string"
          },
          "counts": {
            "type": "object"
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RowResult"
            }
          }
        }
      },
      "StoredListing": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "external_id": {
            "type": "string"
          },
          "environment": {
            "enum": [
              "test",
              "live"
            ]
          },
          "type": {
            "type": "string"
          },
          "destinations": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "status": {
            "type": "string"
          },
          "review_notes": {
            "type": [
              "string",
              "null"
            ]
          },
          "checks": {
            "type": "object"
          },
          "possible_duplicate_of": {
            "type": [
              "object",
              "null"
            ]
          },
          "title": {
            "type": "string"
          },
          "city": {
            "type": [
              "string",
              "null"
            ]
          },
          "price_cents": {
            "type": [
              "integer",
              "null"
            ]
          },
          "currency": {
            "type": [
              "string",
              "null"
            ]
          },
          "starts_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "ends_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "expires_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "published_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "version": {
            "type": "integer"
          },
          "source": {
            "type": "string"
          },
          "listing": {
            "$ref": "#/components/schemas/Listing"
          },
          "created_at": {
            "type": "string"
          },
          "updated_at": {
            "type": "string"
          }
        }
      },
      "FeedMapping": {
        "type": "object",
        "properties": {
          "items_path": {
            "type": "string",
            "description": "JSON/XML: dot path to the record list"
          },
          "fields": {
            "type": "object",
            "additionalProperties": {
              "oneOf": [
                {
                  "type": "string"
                },
                {
                  "type": "object",
                  "properties": {
                    "path": {
                      "type": "string"
                    },
                    "const": {},
                    "template": {
                      "type": "string"
                    },
                    "split": {
                      "type": "string"
                    },
                    "number": {
                      "type": "boolean"
                    },
                    "lower": {
                      "type": "boolean"
                    }
                  }
                }
              ]
            },
            "description": "canonical target path → source path / rule"
          },
          "defaults": {
            "type": "object",
            "description": "Partial listing merged under every mapped record"
          }
        }
      },
      "FeedInput": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "url": {
            "type": "string"
          },
          "format": {
            "enum": [
              "json",
              "csv",
              "xml"
            ]
          },
          "mapping": {
            "$ref": "#/components/schemas/FeedMapping"
          },
          "schedule": {
            "enum": [
              "manual",
              "hourly",
              "daily"
            ]
          },
          "remove_missing": {
            "type": "boolean"
          },
          "active": {
            "type": "boolean"
          }
        }
      },
      "Feed": {
        "allOf": [
          {
            "$ref": "#/components/schemas/FeedInput"
          },
          {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "environment": {
                "type": "string"
              },
              "last_run_at": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "last_status": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "next_run_at": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          }
        ]
      },
      "SyncRun": {
        "type": "object",
        "properties": {
          "run_id": {
            "type": "string"
          },
          "status": {
            "enum": [
              "running",
              "ok",
              "partial",
              "failed"
            ]
          },
          "counts": {
            "type": "object"
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "row": {
                  "type": "integer"
                },
                "external_id": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "errors": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/RowError"
                  }
                }
              }
            }
          },
          "message": {
            "type": "string"
          }
        }
      },
      "Taxonomy": {
        "type": "object",
        "properties": {
          "version": {
            "type": "string"
          },
          "mains": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "destinations": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "categories": {
            "type": "object"
          },
          "cities": {
            "type": "array",
            "items": {
              "type": "object"
            }
          }
        }
      },
      "WebhookEvent": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "type": {
            "type": "string"
          },
          "environment": {
            "type": "string"
          },
          "created_at": {
            "type": "string"
          },
          "delivery_id": {
            "type": "string"
          },
          "data": {
            "type": "object",
            "properties": {
              "listing_id": {
                "type": "string"
              },
              "external_id": {
                "type": "string"
              },
              "type": {
                "type": "string"
              },
              "status": {
                "type": "string"
              },
              "previous_status": {
                "type": "string"
              },
              "review_notes": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "destinations": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              },
              "details": {},
              "request_id": {
                "type": "string"
              }
            }
          }
        }
      }
    }
  }
}