{
  "openapi": "3.0.0",
  "info": {
    "title": "Growwer API",
    "description": "The Growwer customer API. Authenticate every call with an API key created on\nyour profile page, sent as `Authorization: Bearer <key>`. A read key can call\nevery GET operation; writes need a read and write key and an\n`Idempotency-Key` header.\n\nIdempotency: use a new `Idempotency-Key` (1 to 255 printable ASCII\ncharacters without spaces) for each operation and reuse it only to retry that same\noperation. Keys belong to your account, not to one API key.\n- A successful write is stored for 30 days: a retry with the same key and\n  the same request replays its response with `Idempotent-Replayed: true`\n  and does nothing again.\n- A refused write (4xx) has no effect and releases its key: once you fix the\n  cause, retry with the same key and the write runs.\n- A failed write (5xx) may have taken effect, so it is never run again under\n  its key: a retry gets 409 `idempotency_outcome_unknown`. Check whether it\n  took effect before retrying with a new key.\n- A retry while the first request is still running gets 409\n  `idempotency_request_in_progress`. A request still running after 5 minutes\n  is treated as failed: a retry gets 409 `idempotency_outcome_unknown`.\n- The same key with a different request (method, path, query or body) gets\n  409 `idempotency_key_reused`. A write without the header gets 400\n  `idempotency_key_required`.\n\nEvery response carries `X-Request-Id`. Errors share one shape,\n`{code, message, requestId, details?}`. Money is integer cents plus a\ncurrency code and dates are ISO-8601.\n",
    "termsOfService": "https://growwer.com/legal/terms-of-use/",
    "contact": {
      "name": "Growwer Support",
      "url": "https://growwer.com/contact/",
      "email": "support@growwer.com"
    },
    "license": {
      "name": "Proprietary",
      "url": "https://growwer.com/legal/terms-of-use/"
    },
    "version": "1"
  },
  "servers": [
    {
      "url": "https://tool.growwer.com",
      "description": "Production"
    }
  ],
  "paths": {
    "/api/v1/me": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "Your account",
        "description": "Profile basics, the buyer and seller balances, whether your seller account is restricted, whether the catalogue is open to you, and whether you have a managed service.",
        "operationId": "getMe",
        "responses": {
          "200": {
            "description": "Your account.",
            "content": {
              "application/json": {
                "schema": {
                  "required": [
                    "id",
                    "email",
                    "firstName",
                    "language",
                    "createdAt",
                    "buyer",
                    "seller",
                    "catalogue",
                    "managedService"
                  ],
                  "properties": {
                    "id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "email": {
                      "type": "string",
                      "format": "email"
                    },
                    "firstName": {
                      "type": "string"
                    },
                    "language": {
                      "description": "The language Growwer writes to you in.",
                      "type": "string",
                      "example": "en"
                    },
                    "createdAt": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "buyer": {
                      "required": [
                        "balance"
                      ],
                      "properties": {
                        "balance": {
                          "$ref": "#/components/schemas/Balance"
                        }
                      },
                      "type": "object"
                    },
                    "seller": {
                      "required": [
                        "balance",
                        "restricted",
                        "onHoliday",
                        "holidayEndDate"
                      ],
                      "properties": {
                        "balance": {
                          "$ref": "#/components/schemas/Balance"
                        },
                        "restricted": {
                          "description": "Whether your seller account is restricted: it accepts no orders and its balance is held. Contact support for the reason.",
                          "type": "boolean"
                        },
                        "onHoliday": {
                          "description": "Whether you are on holiday: your medias take no orders. Set it with PUT /seller/holiday.",
                          "type": "boolean"
                        },
                        "holidayEndDate": {
                          "description": "The day your holiday ends, at 00:00 of that day in Growwer's server time, or null when you are not on holiday or end it yourself.",
                          "type": "string",
                          "format": "date",
                          "nullable": true
                        }
                      },
                      "type": "object"
                    },
                    "catalogue": {
                      "required": [
                        "eligible"
                      ],
                      "properties": {
                        "eligible": {
                          "description": "Whether the catalogue operations (tag Catalogue: searching a project's medias, flash offers and media details) are open to you. They are open to accounts with recent completed orders, as buyer or as seller; until then they answer 403 `catalogue_requires_recent_order`. A media you have ordered is always readable with GET /medias/{id}.",
                          "type": "boolean"
                        }
                      },
                      "type": "object"
                    },
                    "managedService": {
                      "required": [
                        "active"
                      ],
                      "properties": {
                        "active": {
                          "description": "Whether you have a managed service: Growwer's team runs link building campaigns for you (tag Managed services). With one, request a new campaign with POST /managed-service/campaign-requests; without one, ask about the service with POST /managed-service/info-requests.",
                          "type": "boolean"
                        }
                      },
                      "type": "object"
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/vocabulary": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "Codes and names",
        "description": "The countries, languages, topics, product types, link types and order states that other operations take and return. Names are in English.",
        "operationId": "getVocabulary",
        "responses": {
          "200": {
            "description": "Every code, with its English name where it has one.",
            "content": {
              "application/json": {
                "schema": {
                  "required": [
                    "countries",
                    "languages",
                    "topics",
                    "productTypes",
                    "linkTypes",
                    "orderStates"
                  ],
                  "properties": {
                    "countries": {
                      "description": "ISO 3166-1 alpha-2 codes.",
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CodeName"
                      }
                    },
                    "languages": {
                      "description": "ISO 639 codes, as the web's language selectors offer them.",
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CodeName"
                      }
                    },
                    "topics": {
                      "type": "array",
                      "items": {
                        "required": [
                          "id",
                          "name"
                        ],
                        "properties": {
                          "id": {
                            "type": "integer"
                          },
                          "name": {
                            "type": "string"
                          }
                        },
                        "type": "object"
                      }
                    },
                    "productTypes": {
                      "description": "What an order buys: a sponsored post, or a link added to an existing page.",
                      "type": "array",
                      "items": {
                        "type": "string",
                        "enum": [
                          "post_order",
                          "link_addition_order"
                        ]
                      }
                    },
                    "linkTypes": {
                      "type": "array",
                      "items": {
                        "type": "string",
                        "enum": [
                          "dofollow",
                          "nofollow",
                          "citation"
                        ]
                      }
                    },
                    "orderStates": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/projects/{id}/saved-filters/{filterId}/media-count": {
      "get": {
        "tags": [
          "Saved filters"
        ],
        "summary": "Count the medias of a saved filter",
        "description": "How many medias of the project's catalogue one of your saved filters matches: the `total` of GET /projects/{id}/medias with its `savedFilterId`. The number is cached for up to 24 hours, and it can differ from the count the web shows, which is not limited to the project's catalogue. A filter saved on the web that uses a filter the API does not support is refused with 422 `saved_filter_unsupported`.",
        "operationId": "countSavedFilterMedias",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "The project.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "filterId",
            "in": "path",
            "description": "The saved filter.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The number of matching medias.",
            "content": {
              "application/json": {
                "schema": {
                  "required": [
                    "count"
                  ],
                  "properties": {
                    "count": {
                      "type": "integer",
                      "minimum": 0
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "description": "The saved filter uses a web filter the API does not support (code `saved_filter_unsupported`); `details.field` names it.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/projects/{id}/saved-filters": {
      "get": {
        "tags": [
          "Saved filters"
        ],
        "summary": "List the saved filters of a project",
        "description": "Your saved filters of one of your projects, newest first, including those saved on the web. A project has at most 100. Apply one with `savedFilterId` on GET /projects/{id}/medias.",
        "operationId": "listSavedFilters",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "The project.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The saved filters and how many there are.",
            "content": {
              "application/json": {
                "schema": {
                  "required": [
                    "items",
                    "total"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/SavedFilter"
                      }
                    },
                    "total": {
                      "type": "integer"
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      },
      "post": {
        "tags": [
          "Saved filters"
        ],
        "summary": "Save a filter",
        "description": "Saves a catalogue search of one of your projects, which then also appears on the web. `filters` takes the filter parameters of GET /projects/{id}/medias, and `source`, with the same values; lists may be JSON arrays and flags JSON booleans. With `notificationFrequency`, Growwer emails you new medias that match. A project has at most 100 saved filters and an account 500.",
        "operationId": "createSavedFilter",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "The project.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "required": [
                  "name",
                  "filters"
                ],
                "properties": {
                  "name": {
                    "description": "1 to 255 characters.",
                    "type": "string",
                    "maxLength": 255
                  },
                  "filters": {
                    "description": "At least one filter parameter of GET /projects/{id}/medias, or `source`, by name.",
                    "type": "object",
                    "example": {
                      "language": [
                        "es"
                      ],
                      "minDomainRating": 30,
                      "favourite": true
                    },
                    "additionalProperties": true
                  },
                  "notificationFrequency": {
                    "description": "Email new matching medias this often. Omit it for no emails.",
                    "type": "string",
                    "enum": [
                      "daily",
                      "weekly",
                      "monthly"
                    ]
                  }
                },
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The saved filter.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SavedFilter"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "The project already has 100 saved filters, or the account 500 (code `saved_filter_limit_reached`), or the `Idempotency-Key` conflicts (codes `idempotency_key_reused`, `idempotency_request_in_progress`, `idempotency_outcome_unknown`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/projects/{id}/saved-filters/{filterId}": {
      "delete": {
        "tags": [
          "Saved filters"
        ],
        "summary": "Delete a saved filter",
        "description": "Deletes one of your saved filters of one of your projects, including one saved on the web. Its notifications stop.",
        "operationId": "deleteSavedFilter",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "The project.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "filterId",
            "in": "path",
            "description": "The saved filter.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "204": {
            "description": "The saved filter was deleted."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/IdempotencyConflict"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/projects/{id}/discards/{mediaId}": {
      "put": {
        "tags": [
          "Catalogue"
        ],
        "summary": "Discard a media for a project",
        "description": "Discards a media for one of your projects, as the web does. Discarding it again changes nothing. The media must be one the catalogue shows for the project: another media, including one of your own as a seller, is answered as not found.",
        "operationId": "discardMedia",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "The project.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "mediaId",
            "in": "path",
            "description": "The media.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "204": {
            "description": "The media is discarded for the project."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/IdempotencyConflict"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      },
      "delete": {
        "tags": [
          "Catalogue"
        ],
        "summary": "Restore a discarded media for a project",
        "description": "Restores a media you discarded for one of your projects. Restoring one that is not discarded changes nothing. It works for any media, even one the catalogue no longer shows.",
        "operationId": "undiscardMedia",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "The project.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "mediaId",
            "in": "path",
            "description": "The media.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "204": {
            "description": "The media is not discarded for the project."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/IdempotencyConflict"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/projects/{id}/favourites/{mediaId}": {
      "put": {
        "tags": [
          "Catalogue"
        ],
        "summary": "Add a media to the favourites of a project",
        "description": "Marks a media as a favourite of one of your projects, as the heart on the web does. Adding a favourite again changes nothing. The media must be one the catalogue shows for the project: another media, including one of your own as a seller, is answered as not found.",
        "operationId": "favouriteMedia",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "The project.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "mediaId",
            "in": "path",
            "description": "The media.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "204": {
            "description": "The media is a favourite of the project."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/IdempotencyConflict"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      },
      "delete": {
        "tags": [
          "Catalogue"
        ],
        "summary": "Remove a media from the favourites of a project",
        "description": "Removes a media from the favourites of one of your projects. Removing one that is not a favourite changes nothing. It works for any media, even one the catalogue no longer shows.",
        "operationId": "unfavouriteMedia",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "The project.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "mediaId",
            "in": "path",
            "description": "The media.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "204": {
            "description": "The media is not a favourite of the project."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/IdempotencyConflict"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/medias/{id}": {
      "get": {
        "tags": [
          "Catalogue"
        ],
        "summary": "Get a media",
        "description": "One media of the catalogue: an active, public media. A media you have ordered is always readable, even if it has since left the catalogue, and is open to every account. Otherwise the catalogue is open to accounts with recent completed orders (see `catalogue.eligible` on GET /me), and the media counts towards the distinct medias the account may see per day (UTC). For the media's state in one of your projects, search the project with GET /projects/{id}/medias.",
        "operationId": "getCatalogueMedia",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "The media.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The media.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CatalogueMedia"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CatalogueForbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/flash-offers": {
      "get": {
        "tags": [
          "Catalogue"
        ],
        "summary": "List flash offers",
        "description": "The medias on a flash offer, a time-limited discount, in the catalogue of one of your projects. It is GET /projects/{id}/medias with `flashOffer=true`, and takes the same parameters except `flashOffer` and `savedFilterId`. The catalogue access and the daily distinct-media limit of that operation apply.",
        "operationId": "listFlashOffers",
        "parameters": [
          {
            "name": "projectId",
            "in": "query",
            "description": "The project to search flash offers for.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "$ref": "#/components/parameters/CatalogueSource"
          },
          {
            "$ref": "#/components/parameters/CatalogueSort"
          },
          {
            "$ref": "#/components/parameters/CatalogueDomain"
          },
          {
            "$ref": "#/components/parameters/CatalogueWebsiteType"
          },
          {
            "$ref": "#/components/parameters/CatalogueLanguage"
          },
          {
            "$ref": "#/components/parameters/CatalogueCountry"
          },
          {
            "$ref": "#/components/parameters/CatalogueTopics"
          },
          {
            "$ref": "#/components/parameters/CatalogueNotBannedTopics"
          },
          {
            "$ref": "#/components/parameters/CatalogueMinTraffic"
          },
          {
            "$ref": "#/components/parameters/CatalogueMaxTraffic"
          },
          {
            "$ref": "#/components/parameters/CatalogueTrafficTrendUpward"
          },
          {
            "$ref": "#/components/parameters/CatalogueMinDomainRating"
          },
          {
            "$ref": "#/components/parameters/CatalogueMaxDomainRating"
          },
          {
            "$ref": "#/components/parameters/CatalogueMinLinkedToReferringRatio"
          },
          {
            "$ref": "#/components/parameters/CatalogueMaxLinkedToReferringRatio"
          },
          {
            "$ref": "#/components/parameters/CatalogueMinPostPrice"
          },
          {
            "$ref": "#/components/parameters/CatalogueMaxPostPrice"
          },
          {
            "$ref": "#/components/parameters/CataloguePostLinkType"
          },
          {
            "$ref": "#/components/parameters/CataloguePromotedSocialNetwork"
          },
          {
            "$ref": "#/components/parameters/CatalogueWithoutAdvertisingLabel"
          },
          {
            "$ref": "#/components/parameters/CatalogueHomepageListing"
          },
          {
            "$ref": "#/components/parameters/CatalogueHasLinkAddition"
          },
          {
            "$ref": "#/components/parameters/CatalogueMinLinkAdditionPrice"
          },
          {
            "$ref": "#/components/parameters/CatalogueMaxLinkAdditionPrice"
          },
          {
            "$ref": "#/components/parameters/CatalogueLinkAdditionLinkType"
          },
          {
            "$ref": "#/components/parameters/CatalogueRecommended"
          },
          {
            "$ref": "#/components/parameters/CatalogueFavourite"
          },
          {
            "$ref": "#/components/parameters/CatalogueRequested"
          },
          {
            "$ref": "#/components/parameters/CatalogueBought"
          },
          {
            "$ref": "#/components/parameters/CatalogueDiscarded"
          },
          {
            "$ref": "#/components/parameters/CatalogueNew"
          },
          {
            "$ref": "#/components/parameters/CatalogueRanksGoalKeyword"
          },
          {
            "$ref": "#/components/parameters/CatalogueRanksAiKeyword"
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Medias per page, 1 to 100.",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 20,
              "maximum": 100,
              "minimum": 1
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Medias to skip, at most 99900.",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 0,
              "maximum": 99900,
              "minimum": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of flash offers and how many there are in all.",
            "content": {
              "application/json": {
                "schema": {
                  "required": [
                    "items",
                    "total"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ProjectCatalogueMedia"
                      }
                    },
                    "total": {
                      "type": "integer"
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CatalogueForbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/projects/{id}/media-requests": {
      "post": {
        "tags": [
          "Catalogue"
        ],
        "summary": "Request specific medias for a project",
        "description": "Asks Growwer to find the medias of these domains for one of your projects, as the \"request specific domains\" form on the web does. Each entry may be a domain or a URL; it is read as its full domain, lowercased. Repeated domains are requested once, and a domain already requested changes nothing. Up to 200 distinct domains per call. They then appear in the project's catalogue with `project.requested` true (`requested=true` on GET /projects/{id}/medias) once Growwer lists them.",
        "operationId": "requestMedias",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "The project.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "required": [
                  "domains"
                ],
                "properties": {
                  "domains": {
                    "description": "Domains or URLs, 1 to 200 distinct domains.",
                    "type": "array",
                    "items": {
                      "type": "string",
                      "example": "example.com"
                    }
                  }
                },
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The domains were requested: each distinct domain, as Growwer read it.",
            "content": {
              "application/json": {
                "schema": {
                  "required": [
                    "domains"
                  ],
                  "properties": {
                    "domains": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/IdempotencyConflict"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/projects/{id}/medias": {
      "get": {
        "tags": [
          "Catalogue"
        ],
        "summary": "Search the catalogue for a project",
        "description": "The medias the catalogue offers for one of your projects, as the web lists them, with each media's state in the project. Filter with the parameters below, which all combine, or apply one of your saved filters with `savedFilterId` alone. The catalogue is open to accounts with recent completed orders (see `catalogue.eligible` on GET /me), and each account can see a limited number of distinct medias per day (UTC) across the catalogue operations; medias seen again the same day are free.",
        "operationId": "searchProjectMedias",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "The project.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "$ref": "#/components/parameters/CatalogueSource"
          },
          {
            "$ref": "#/components/parameters/CatalogueSort"
          },
          {
            "name": "savedFilterId",
            "in": "query",
            "description": "Apply one of your saved filters of this project, including one saved on the web, instead of the other parameters. Do not combine it with any filter, `source` or `sort`. A filter saved on the web that uses a filter the API does not support is refused with 422 `saved_filter_unsupported`.",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "$ref": "#/components/parameters/CatalogueDomain"
          },
          {
            "$ref": "#/components/parameters/CatalogueWebsiteType"
          },
          {
            "$ref": "#/components/parameters/CatalogueLanguage"
          },
          {
            "$ref": "#/components/parameters/CatalogueCountry"
          },
          {
            "$ref": "#/components/parameters/CatalogueTopics"
          },
          {
            "$ref": "#/components/parameters/CatalogueNotBannedTopics"
          },
          {
            "$ref": "#/components/parameters/CatalogueMinTraffic"
          },
          {
            "$ref": "#/components/parameters/CatalogueMaxTraffic"
          },
          {
            "$ref": "#/components/parameters/CatalogueTrafficTrendUpward"
          },
          {
            "$ref": "#/components/parameters/CatalogueMinDomainRating"
          },
          {
            "$ref": "#/components/parameters/CatalogueMaxDomainRating"
          },
          {
            "$ref": "#/components/parameters/CatalogueMinLinkedToReferringRatio"
          },
          {
            "$ref": "#/components/parameters/CatalogueMaxLinkedToReferringRatio"
          },
          {
            "$ref": "#/components/parameters/CatalogueMinPostPrice"
          },
          {
            "$ref": "#/components/parameters/CatalogueMaxPostPrice"
          },
          {
            "$ref": "#/components/parameters/CataloguePostLinkType"
          },
          {
            "$ref": "#/components/parameters/CataloguePromotedSocialNetwork"
          },
          {
            "$ref": "#/components/parameters/CatalogueWithoutAdvertisingLabel"
          },
          {
            "$ref": "#/components/parameters/CatalogueHomepageListing"
          },
          {
            "$ref": "#/components/parameters/CatalogueHasLinkAddition"
          },
          {
            "$ref": "#/components/parameters/CatalogueMinLinkAdditionPrice"
          },
          {
            "$ref": "#/components/parameters/CatalogueMaxLinkAdditionPrice"
          },
          {
            "$ref": "#/components/parameters/CatalogueLinkAdditionLinkType"
          },
          {
            "$ref": "#/components/parameters/CatalogueRecommended"
          },
          {
            "$ref": "#/components/parameters/CatalogueFavourite"
          },
          {
            "$ref": "#/components/parameters/CatalogueRequested"
          },
          {
            "$ref": "#/components/parameters/CatalogueFlashOffer"
          },
          {
            "$ref": "#/components/parameters/CatalogueBought"
          },
          {
            "$ref": "#/components/parameters/CatalogueDiscarded"
          },
          {
            "$ref": "#/components/parameters/CatalogueNew"
          },
          {
            "$ref": "#/components/parameters/CatalogueRanksGoalKeyword"
          },
          {
            "$ref": "#/components/parameters/CatalogueRanksAiKeyword"
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Medias per page, 1 to 100.",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 20,
              "maximum": 100,
              "minimum": 1
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Medias to skip, at most 99900.",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 0,
              "maximum": 99900,
              "minimum": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of matching medias and how many match in all.",
            "content": {
              "application/json": {
                "schema": {
                  "required": [
                    "items",
                    "total"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ProjectCatalogueMedia"
                      }
                    },
                    "total": {
                      "type": "integer"
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/CatalogueForbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "description": "A parameter is not valid (code `validation_failed`; `details.fields` names it), or the saved filter uses a web filter the API does not support (code `saved_filter_unsupported`; `details.field` names it).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/files": {
      "post": {
        "tags": [
          "Files"
        ],
        "summary": "Upload a file",
        "description": "Uploads a document (odt, doc, docx or txt, up to 8 MB) for a later write to reference by its `id`. A file belongs to you, can be used by one write, and expires 24 hours after it was uploaded; an expired or used file is answered like an unknown one.",
        "operationId": "uploadFile",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "required": [
                  "file"
                ],
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary"
                  }
                },
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The file, stored until `expiresAt`.",
            "content": {
              "application/json": {
                "schema": {
                  "required": [
                    "id",
                    "name",
                    "size",
                    "expiresAt"
                  ],
                  "properties": {
                    "id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "name": {
                      "description": "The name the file was uploaded with.",
                      "type": "string"
                    },
                    "size": {
                      "description": "Bytes.",
                      "type": "integer"
                    },
                    "expiresAt": {
                      "type": "string",
                      "format": "date-time"
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/IdempotencyConflict"
          },
          "422": {
            "description": "No file was sent as the `file` field, or it is too large, not an odt, doc, docx or txt document, or its name is longer than 255 characters (code `validation_failed`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/invoices/{id}/pdf": {
      "get": {
        "tags": [
          "Buyer money"
        ],
        "summary": "Download an invoice",
        "description": "The PDF of one of your invoices.",
        "operationId": "getInvoicePdf",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The invoice.",
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/invoices": {
      "get": {
        "tags": [
          "Buyer money"
        ],
        "summary": "List your invoices",
        "description": "The invoices of your top-ups, newest first.",
        "operationId": "listInvoices",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "description": "Invoices per page, 1 to 100.",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 20,
              "maximum": 100,
              "minimum": 1
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Invoices to skip.",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 0,
              "minimum": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of your invoices and how many you have in all.",
            "content": {
              "application/json": {
                "schema": {
                  "required": [
                    "items",
                    "total"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Invoice"
                      }
                    },
                    "total": {
                      "type": "integer"
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/managed-service/campaigns/{id}/proposals/estimate": {
      "post": {
        "tags": [
          "Managed services"
        ],
        "summary": "Estimate accepting proposals",
        "description": "Totals the campaign's accepted proposals that still await their order and the `proposed` ones you name in `accept`, and compares the total with your wallet's available balance. Each proposal counts at its `currentPrice`, or at its `proposedPrice` when the media no longer offers the service. Nothing is accepted, charged or reserved, so a read-only key may call it and it takes no Idempotency-Key.\n\nThe estimate is advisory: accepting a proposal charges nothing. The team charges your wallet when it places the order for an accepted proposal, and the same balance pays for the orders you place yourself.",
        "operationId": "estimateManagedServiceProposals",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ManagedServiceProposalsEstimateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The totals and how your wallet covers them.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManagedServiceProposalsEstimate"
                }
              }
            }
          },
          "400": {
            "description": "The body is not a JSON object (code `invalid_json`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "The campaign is not yours, or a proposal named in `accept` is not one of the campaign's (code `not_found`, with `details.proposalId`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "A proposal named in `accept` is not awaiting your review (code `invalid_state`, with `details.proposalIds`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/managed-service/campaigns/{id}": {
      "get": {
        "tags": [
          "Managed services"
        ],
        "summary": "Get a managed service campaign",
        "operationId": "getManagedServiceCampaign",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The campaign.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManagedServiceCampaign"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/managed-service/campaigns/{id}/proposals-summary": {
      "get": {
        "tags": [
          "Managed services"
        ],
        "summary": "Download the summary of a campaign's proposals",
        "description": "The PDF the campaign page offers: the proposals awaiting your review, accepted or being published, newest first, in your language. With `extended=true` it also shows each proposal's price, the price it was proposed at (`proposedPrice`).",
        "operationId": "getManagedServiceProposalsSummary",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "extended",
            "in": "query",
            "description": "Whether to show the prices.",
            "required": false,
            "schema": {
              "type": "string",
              "default": "false",
              "enum": [
                "true",
                "false"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The summary.",
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/managed-service/campaigns": {
      "get": {
        "tags": [
          "Managed services"
        ],
        "summary": "List your managed service campaigns",
        "description": "The campaigns your managed service runs for you, newest first. Without a managed service the list is empty: GET /me says whether you have one.",
        "operationId": "listManagedServiceCampaigns",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "description": "Campaigns per page, 1 to 100.",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 20,
              "maximum": 100,
              "minimum": 1
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Campaigns to skip.",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 0,
              "minimum": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of your campaigns and how many you have in all.",
            "content": {
              "application/json": {
                "schema": {
                  "required": [
                    "items",
                    "total"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ManagedServiceCampaign"
                      }
                    },
                    "total": {
                      "type": "integer"
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/managed-service/campaigns/{id}/proposals": {
      "get": {
        "tags": [
          "Managed services"
        ],
        "summary": "List the proposals of a campaign",
        "description": "The medias the team proposes for the campaign, newest first. Those `proposed` await your review (POST /managed-service/campaigns/{id}/proposals/review).",
        "operationId": "listManagedServiceProposals",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "state",
            "in": "query",
            "description": "Only proposals in these states, comma-separated: `proposed`, `accepted`, `cancelled`, `purchase_started`, `purchase_finished`.",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "proposed,accepted"
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Proposals per page, 1 to 100.",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 20,
              "maximum": 100,
              "minimum": 1
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Proposals to skip.",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 0,
              "minimum": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the campaign's proposals and how many match in all.",
            "content": {
              "application/json": {
                "schema": {
                  "required": [
                    "items",
                    "total"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ManagedServiceProposal"
                      }
                    },
                    "total": {
                      "type": "integer"
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/managed-service/campaign-requests": {
      "post": {
        "tags": [
          "Managed services"
        ],
        "summary": "Request a new campaign",
        "description": "Asks your account manager for a new campaign, as the managed service page does: the team emails you to agree on it. For accounts with a managed service (GET /me `managedService.active`); without one, POST /managed-service/info-requests asks about the service.\n\nYou may send 5 such requests per UTC day through the API. Past them it answers 429 `managed_service_request_limit_reached`, with `Retry-After` the time to the next UTC midnight. A request that is refused (4xx) does not count; one that fails on the server (5xx) does, as it may have been sent.",
        "operationId": "requestManagedServiceCampaign",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ManagedServiceRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "The request was sent.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManagedServiceRequestSent"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The key is read-only (code `insufficient_capability`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "You have no managed service yet (code `managed_service_required`), or the `Idempotency-Key` conflicts (codes `idempotency_key_reused`, `idempotency_request_in_progress`, `idempotency_outcome_unknown`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/managed-service/info-requests": {
      "post": {
        "tags": [
          "Managed services"
        ],
        "summary": "Ask about the managed service",
        "description": "Asks the team about the managed service for your website, as the managed service landing page does: the team contacts you. For accounts without a managed service (GET /me `managedService.active`); with one, POST /managed-service/campaign-requests requests a new campaign.\n\nYou may send 5 such requests per UTC day through the API. Past them it answers 429 `managed_service_request_limit_reached`, with `Retry-After` the time to the next UTC midnight. A request that is refused (4xx) does not count; one that fails on the server (5xx) does, as it may have been sent.",
        "operationId": "requestManagedServiceInfo",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ManagedServiceRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "The request was sent.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManagedServiceRequestSent"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The key is read-only (code `insufficient_capability`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "You already have a managed service (code `managed_service_exists`), or the `Idempotency-Key` conflicts (codes `idempotency_key_reused`, `idempotency_request_in_progress`, `idempotency_outcome_unknown`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/managed-service/campaigns/{id}/proposals/review": {
      "post": {
        "tags": [
          "Managed services"
        ],
        "summary": "Accept or reject proposals",
        "description": "Decides on every proposal of the campaign that awaits your review (`state` `proposed`), as the campaign page does: name each one once, with `accept` or `reject`, and a comment for the team to reject one. Their order in the body does not matter. Accepting charges nothing: the team places the orders for the accepted proposals and your wallet pays for them then. POST /managed-service/campaigns/{id}/proposals/estimate says what they would cost.\n\nWhen every proposal is accepted the campaign moves to `proposal_accepted`; when one is rejected the team is told and prepares others. A proposal someone else moved on the campaign page while the request ran is answered in the state it reached.",
        "operationId": "reviewManagedServiceProposals",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ManagedServiceProposalReviewRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The campaign and the proposals you reviewed, as they now are.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManagedServiceProposalReview"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The key is read-only (code `insufficient_capability`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The campaign is not yours, or a proposal named is not one of the campaign's (code `not_found`, with `details.proposalId`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "No proposal of the campaign awaits your review (code `no_pending_proposals`), or a proposal named does not (code `invalid_state`, with `details.proposalIds`), or the `Idempotency-Key` conflicts (codes `idempotency_key_reused`, `idempotency_request_in_progress`, `idempotency_outcome_unknown`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "The body is invalid (code `validation_failed`), or it leaves out proposals awaiting your review (code `review_incomplete`, with `details.missingProposalIds`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/orders/{id}/approve": {
      "post": {
        "tags": [
          "Orders"
        ],
        "summary": "Approve an order's delivery",
        "description": "Approves the delivery of an order whose `pendingAction` is yours to review the delivery, as the web does. The order finishes and the seller is paid. It takes no body.",
        "operationId": "approveOrder",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "The order, approved.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Order"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The key is read-only (code `insufficient_capability`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "The order is not pending your review of its delivery (code `invalid_state`), or the `Idempotency-Key` conflicts (codes `idempotency_key_reused`, `idempotency_request_in_progress`, `idempotency_outcome_unknown`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/orders/{id}/approve-draft": {
      "post": {
        "tags": [
          "Orders"
        ],
        "summary": "Approve a draft",
        "description": "Approves the draft of a post order whose `pendingAction` is yours to review the draft (GET /orders/{id}/draft downloads it), as the web does. The seller then publishes it. It takes no body.",
        "operationId": "approveOrderDraft",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "The order, with its draft approved.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Order"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The key is read-only (code `insufficient_capability`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "The order is not a post order with a draft pending your review (code `invalid_state`), or the `Idempotency-Key` conflicts (codes `idempotency_key_reused`, `idempotency_request_in_progress`, `idempotency_outcome_unknown`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/orders/{id}/cancel": {
      "post": {
        "tags": [
          "Orders"
        ],
        "summary": "Cancel an order",
        "description": "Cancels an order the seller has not accepted yet (`state` `pending_acceptance`), as the web does. Its price returns to your wallet's available balance, and the seller is told your reason.",
        "operationId": "cancelOrder",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OrderActionReason"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The order, cancelled.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Order"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The key is read-only (code `insufficient_capability`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "The seller has already accepted or refused the order, or it has finished (code `invalid_state`), or the `Idempotency-Key` conflicts (codes `idempotency_key_reused`, `idempotency_request_in_progress`, `idempotency_outcome_unknown`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/orders": {
      "get": {
        "tags": [
          "Orders"
        ],
        "summary": "List your orders",
        "description": "The orders you bought, newest first by default. To follow your orders, poll with `sort=updatedAt` and `updatedSince` set to the `updatedAt` of the last order you saw: an order moves to the end of that list each time it changes state.",
        "operationId": "listOrders",
        "parameters": [
          {
            "name": "projectId",
            "in": "query",
            "description": "Only the orders of this project of yours.",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "mediaId",
            "in": "query",
            "description": "Only the orders on this media.",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "state",
            "in": "query",
            "description": "Only the orders in one of these states, comma-separated. An unknown state is refused with 422 and the list of valid ones.",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "pending_acceptance,pending_order_delivery"
          },
          {
            "name": "updatedSince",
            "in": "query",
            "description": "Only the orders whose `updatedAt` is at or after this instant, an ISO-8601 date-time with its offset (send `+` as `%2B`).",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "`-createdAt`, newest first, or `updatedAt`, least recently changed first. Orders of the same instant come in id order.",
            "required": false,
            "schema": {
              "type": "string",
              "default": "-createdAt",
              "enum": [
                "-createdAt",
                "updatedAt"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Orders per page, 1 to 100.",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 20,
              "maximum": 100,
              "minimum": 1
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Orders to skip.",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 0,
              "minimum": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of your orders and how many match in all.",
            "content": {
              "application/json": {
                "schema": {
                  "required": [
                    "items",
                    "total"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Order"
                      }
                    },
                    "total": {
                      "type": "integer"
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      },
      "post": {
        "tags": [
          "Orders"
        ],
        "summary": "Place an order",
        "description": "Places an order on a media for one of your projects and pays its price from your wallet's available balance, as ordering on the web does. Estimate the order first (POST /orders/estimate) and send the price it answers as `expectedPrice`: the order is placed only at that price.\n\nPlacing the same order (same project, media, type and price) again within 5 seconds of one still in progress is refused with `duplicate_order`. Its `details.orderId` is the earlier order, or null when that order has finished or was deleted since.\n\nA proposed draft (`proposedDraftFileId`, from POST /files) is used up when the order is placed. If the order is then refused because another request changed your balance, the media or its price, or placed the same order, the file is used up all the same and the refusal's message says so: upload it again before retrying.",
        "operationId": "createOrder",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OrderCreateRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The order, placed and paid. `Location` is its URL.",
            "headers": {
              "Location": {
                "description": "The URL of the new order.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Order"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The key is read-only (code `insufficient_capability`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The project is not yours, or the media does not exist or is not one you can order for this project (code `not_found`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "The order cannot be placed, and nothing was charged:\n- `price_changed`: the price is not `expectedPrice`; `details.currentPrice` is the price.\n- `insufficient_balance`: your available balance does not cover the price; `details` has `required`, `available` and `missing` (Money).\n- `duplicate_order`: the same order was placed seconds ago; `details.orderId` is that order, or null.\n- `seller_on_holiday`: the media is not taking orders right now.\n- `media_topic_not_allowed`: the media does not accept the project's topic.\n- `offer_unavailable`: the media does not offer this type of order.\n- `idempotency_key_reused`, `idempotency_request_in_progress`, `idempotency_outcome_unknown`: the `Idempotency-Key` conflicts.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "The body is not valid (code `validation_failed`, with the messages of each field in `details.fields`), or `proposedDraftFileId` names no file you can use: it does not exist, has expired or was already used (code `file_unusable`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/orders/{id}/briefing": {
      "get": {
        "tags": [
          "Orders"
        ],
        "summary": "Download the draft you attached to an order",
        "description": "The file you attached to the briefing of a post order. 404 when the order has none (`briefing.hasProposedDraft` is false) or the file cannot be read.",
        "operationId": "downloadOrderBriefing",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The file, with its own content type and name.",
            "content": {
              "application/octet-stream": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/orders/{id}/draft": {
      "get": {
        "tags": [
          "Orders"
        ],
        "summary": "Download the draft of an order",
        "description": "The file of the current draft of a post order. 404 when the order has no draft file (`draft.hasFile` is false) or the file cannot be read.",
        "operationId": "downloadOrderDraft",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The file, with its own content type and name.",
            "content": {
              "application/octet-stream": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/orders/estimate": {
      "post": {
        "tags": [
          "Orders"
        ],
        "summary": "Estimate an order",
        "description": "Checks and prices the order POST /orders would place with the same body, without `expectedPrice`, and compares the price with your wallet's available balance. Nothing is placed, charged or used up, so a read-only key may call it and it takes no Idempotency-Key. Send the `price` it answers as `expectedPrice` when you place the order.\n\nThe estimate is refused for the same reasons as the order itself, except a balance that does not cover the price: that is answered here with `sufficientBalance: false` and the `missing` amount.",
        "operationId": "estimateOrder",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OrderEstimateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The price of the order and how your wallet covers it.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrderEstimate"
                }
              }
            }
          },
          "400": {
            "description": "The body is not a JSON object (code `invalid_json`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "The project is not yours, or the media does not exist or is not one you can order for this project (code `not_found`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "The order could not be placed:\n- `seller_on_holiday`: the media is not taking orders right now.\n- `media_topic_not_allowed`: the media does not accept the project's topic.\n- `offer_unavailable`: the media does not offer this type of order.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "The body is not valid (code `validation_failed`, with the messages of each field in `details.fields`), or `proposedDraftFileId` names no file you can use: it does not exist, has expired or was already used (code `file_unusable`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/orders/{id}": {
      "get": {
        "tags": [
          "Orders"
        ],
        "summary": "Get an order",
        "description": "One order you bought, with its briefing, its draft and its state history.",
        "operationId": "getOrder",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The order.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Order"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/orders/{id}/request-draft-update": {
      "post": {
        "tags": [
          "Orders"
        ],
        "summary": "Request changes to a draft",
        "description": "Asks the seller to change the draft of a post order whose `pendingAction` is yours to review the draft, as the web does. The seller is told your reason.",
        "operationId": "requestOrderDraftUpdate",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OrderActionReason"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The order, with its draft back with the seller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Order"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The key is read-only (code `insufficient_capability`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "The order is not a post order with a draft pending your review (code `invalid_state`), or the `Idempotency-Key` conflicts (codes `idempotency_key_reused`, `idempotency_request_in_progress`, `idempotency_outcome_unknown`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/orders/{id}/request-update": {
      "post": {
        "tags": [
          "Orders"
        ],
        "summary": "Request changes to a delivery",
        "description": "Asks the seller to change the delivery of an order whose `pendingAction` is yours to review the delivery, as the web does. The seller is told your reason.",
        "operationId": "requestOrderUpdate",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OrderActionReason"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The order, back with the seller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Order"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The key is read-only (code `insufficient_capability`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "The order is not pending your review of its delivery (code `invalid_state`), or the `Idempotency-Key` conflicts (codes `idempotency_key_reused`, `idempotency_request_in_progress`, `idempotency_outcome_unknown`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/projects": {
      "get": {
        "tags": [
          "Projects"
        ],
        "summary": "List your projects",
        "description": "Your projects, newest first.",
        "operationId": "listProjects",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "description": "Projects per page, 1 to 100.",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 20,
              "maximum": 100,
              "minimum": 1
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Projects to skip.",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 0,
              "minimum": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of your projects and how many you have in all.",
            "content": {
              "application/json": {
                "schema": {
                  "required": [
                    "items",
                    "total"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Project"
                      }
                    },
                    "total": {
                      "type": "integer"
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      },
      "post": {
        "tags": [
          "Projects"
        ],
        "summary": "Create a project",
        "description": "Creates a project for a website, as the web's project creation does. Growwer then analyses it in the background to recommend media: the project is answered with `state: analyzing` and turns `finished` when the analysis ends. Analysis can take hours, and it never finishes when no medium matches the project, so poll GET /projects/{id} with backoff and use `createdAt` to decide when to stop.\n\nEvery value is validated as on the web: `topics`, `language` and `country` take the identifiers GET /vocabulary publishes.\n\nCreating a project also categorises its website through an external service, as the web does. When that service fails the answer is 500, although the project may already be saved, and a retry under the same Idempotency-Key answers 409 `idempotency_outcome_unknown`. After either, list your projects (GET /projects) before retrying with a new key, or you may create a duplicate.",
        "operationId": "createProject",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "required": [
                  "rootUrl",
                  "websiteType",
                  "topics",
                  "language",
                  "promotedProducts"
                ],
                "properties": {
                  "name": {
                    "type": "string",
                    "nullable": true,
                    "maxLength": 255
                  },
                  "rootUrl": {
                    "type": "string",
                    "format": "uri",
                    "example": "https://www.example.com"
                  },
                  "websiteType": {
                    "type": "string",
                    "enum": [
                      "ecommerce",
                      "services",
                      "other"
                    ]
                  },
                  "topics": {
                    "description": "Exactly one topic id from GET /vocabulary.",
                    "type": "array",
                    "items": {
                      "type": "integer"
                    },
                    "maxItems": 1,
                    "minItems": 1
                  },
                  "language": {
                    "description": "A language code from GET /vocabulary.",
                    "type": "string",
                    "example": "es"
                  },
                  "country": {
                    "description": "A country code from GET /vocabulary; omit it or send null for worldwide.",
                    "type": "string",
                    "example": "ES",
                    "nullable": true
                  },
                  "promotedProducts": {
                    "description": "5 to 10 products or services the campaign promotes.",
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "maxItems": 10,
                    "minItems": 5
                  },
                  "userKeywords": {
                    "description": "At most 100 keywords, none with a line break.",
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "maxItems": 100
                  }
                },
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "The project, created and being analysed. `Location` is its URL.",
            "headers": {
              "Location": {
                "description": "The URL of the new project.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Project"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The key is read-only (code `insufficient_capability`), or you have reached the number of projects an account may have without a wallet deposit in the last year (code `project_limit_reached`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "$ref": "#/components/responses/IdempotencyConflict"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/projects/{id}": {
      "get": {
        "tags": [
          "Projects"
        ],
        "summary": "Get a project",
        "description": "One of your projects. Poll it to follow `state` after creating the project.",
        "operationId": "getProject",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The project.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Project"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      },
      "delete": {
        "tags": [
          "Projects"
        ],
        "summary": "Delete a project",
        "description": "Deletes one of your projects. A project with an order in progress cannot be deleted until its orders finish.",
        "operationId": "deleteProject",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "204": {
            "description": "The project was deleted."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "The project has an order in progress (code `invalid_state`), or the `Idempotency-Key` conflicts (codes `idempotency_key_reused`, `idempotency_request_in_progress`, `idempotency_outcome_unknown`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      },
      "patch": {
        "tags": [
          "Projects"
        ],
        "summary": "Edit a project",
        "description": "Changes only the fields you send. `rootUrl` cannot be changed; any field not listed here is refused. Changing `language`, `country`, `promotedProducts` or `topics` makes Growwer categorise the project and work out its target keywords again, in the background.",
        "operationId": "updateProject",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "name": {
                    "description": "Null or an empty string removes the name.",
                    "type": "string",
                    "nullable": true,
                    "maxLength": 255
                  },
                  "websiteType": {
                    "type": "string",
                    "enum": [
                      "ecommerce",
                      "services",
                      "other"
                    ]
                  },
                  "topics": {
                    "description": "Exactly one topic id from GET /vocabulary.",
                    "type": "array",
                    "items": {
                      "type": "integer"
                    },
                    "maxItems": 1,
                    "minItems": 1
                  },
                  "language": {
                    "description": "A language code from GET /vocabulary.",
                    "type": "string"
                  },
                  "country": {
                    "description": "A country code from GET /vocabulary, or null for worldwide.",
                    "type": "string",
                    "nullable": true
                  },
                  "promotedProducts": {
                    "description": "5 to 10 products or services the campaign promotes.",
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "maxItems": 10,
                    "minItems": 5
                  },
                  "userKeywords": {
                    "description": "At most 100 keywords, none with a line break.",
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "maxItems": 100
                  }
                },
                "type": "object",
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The project as edited.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Project"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/IdempotencyConflict"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/seller/holiday": {
      "put": {
        "tags": [
          "Account"
        ],
        "summary": "Set your holiday",
        "description": "Starts, changes or ends your holiday, as the holiday settings of your profile page do. While you are on holiday your medias take no orders. `endDate` is the day your holiday ends, at 00:00 of that day in Growwer's server time, and must be later than now; leave it out, or send null, for a holiday you end yourself. Ending the holiday takes no `endDate`.\n\nA holiday that already is as you ask is answered 200 without a change. A restricted seller account stays on holiday until the restriction is lifted, so any change is refused. Your holiday is also in GET /me.",
        "operationId": "putSellerHoliday",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "required": [
                  "onHoliday"
                ],
                "properties": {
                  "onHoliday": {
                    "type": "boolean"
                  },
                  "endDate": {
                    "type": "string",
                    "format": "date",
                    "example": "2026-12-01",
                    "nullable": true
                  }
                },
                "type": "object",
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Your holiday, as it now is.",
            "content": {
              "application/json": {
                "schema": {
                  "required": [
                    "onHoliday",
                    "endDate"
                  ],
                  "properties": {
                    "onHoliday": {
                      "type": "boolean"
                    },
                    "endDate": {
                      "description": "The day the holiday ends, at 00:00 of that day in Growwer's server time, or null for none.",
                      "type": "string",
                      "format": "date",
                      "nullable": true
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The key is read-only (code `insufficient_capability`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Your seller account is restricted, so its holiday cannot change (code `seller_restricted`), or the `Idempotency-Key` conflicts (codes `idempotency_key_reused`, `idempotency_request_in_progress`, `idempotency_outcome_unknown`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "The body is not valid (code `validation_failed`): an `endDate` that is not a later day, or one sent with `onHoliday` false.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/seller/medias/{id}/apply-competitive-fees": {
      "post": {
        "tags": [
          "Seller medias"
        ],
        "summary": "Set the competitive fees Growwer suggests",
        "description": "Sets your post fees for the media to the competitive fees Growwer suggests, the `competitiveFees` of GET /seller/medias/{id}, as the button on the media edit page does. Each link type you offer gets the suggested fee on each side it already has a fee for; no link type gains a side it did not offer.\n\nTwo differences from the page: a side Growwer has no suggestion for keeps your fee (the page clears it), and the fixed fee the page falls back to when it cannot find a competitive one is never applied (the page applies it). When neither side has a suggestion, nothing changes and the answer is 409 `no_competitive_fees`. When your fees already are the suggested ones, or the suggestion is only for a side none of your link types offers, nothing changes and the answer is 200.\n\nThe fees set are your base fees: a running flash offer keeps discounting them. As with a fee edit, a change of the price may cancel the managed-service proposals accepted for the media whose price it changes. Send no body, or an empty object.",
        "operationId": "applySellerMediaCompetitiveFees",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "The media, with the suggested fees set.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SellerMedia"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The key is read-only (code `insufficient_capability`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "Growwer has no competitive fees to suggest for the media now (code `no_competitive_fees`), or the `Idempotency-Key` conflicts (codes `idempotency_key_reused`, `idempotency_request_in_progress`, `idempotency_outcome_unknown`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "The body is not empty, or the fees set break a rule of the media edit page (code `validation_failed`). Nothing changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/seller/medias/{id}": {
      "get": {
        "tags": [
          "Seller medias"
        ],
        "summary": "Get a media you sell on",
        "description": "One of your medias, with your fees, its extras, the competitive fees Growwer suggests and how it performs. Another seller's media is not found.",
        "operationId": "getSellerMedia",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The media.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SellerMedia"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      },
      "patch": {
        "tags": [
          "Seller medias"
        ],
        "summary": "Edit the fees of a media you sell on",
        "description": "Sets the fees of one of your medias, as the media edit page saves them. Send only the sections you change: a section you send replaces that section wholly, a section you leave out stays as it is.\n\n- `postOffer.pricingOptions` lists every link type you offer for sponsored posts, at least one. A link type you leave out is no longer offered. Each option needs at least one fee, and every option must offer the same sides (written by you, written by the buyer or Growwer), as the page requires. Each fee is at least 1 EUR.\n- `linkAdditionOffer.pricingOptions` lists the link types you offer for adding a link to an existing article; `null` or an empty list stops offering link additions.\n- `extraServices` is the full list of extra services you offer; an empty list removes them all.\n\nThe fees are your base fees, the ones GET /seller/medias/{id} returns: while a flash offer runs, its discount keeps applying on top of them, and `currentCost` shows the result. `currentCost` may be sent back as read and is ignored. Characteristics, topics and comments are not edited here.\n\nAs on the page, a change of the post offer's price may cancel the managed-service proposals accepted for the media whose price it changes, and raising the price above the best competitor's tells Growwer's support team. A restricted seller account may edit its fees.",
        "operationId": "updateSellerMedia",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "postOffer": {
                    "required": [
                      "pricingOptions"
                    ],
                    "properties": {
                      "pricingOptions": {
                        "type": "array",
                        "items": {
                          "required": [
                            "linkType"
                          ],
                          "properties": {
                            "linkType": {
                              "type": "string",
                              "enum": [
                                "dofollow",
                                "nofollow",
                                "citation"
                              ]
                            },
                            "feeWhenSellerWritesPost": {
                              "description": "What you are paid for a post you write; null or left out when you do not offer it.",
                              "allOf": [
                                {
                                  "$ref": "#/components/schemas/MoneyOrNull"
                                }
                              ]
                            },
                            "feeWhenSellerDoesNotWritePost": {
                              "description": "What you are paid for a post the buyer or Growwer writes; null or left out when you do not offer it.",
                              "allOf": [
                                {
                                  "$ref": "#/components/schemas/MoneyOrNull"
                                }
                              ]
                            }
                          },
                          "type": "object"
                        },
                        "minItems": 1
                      }
                    },
                    "type": "object",
                    "additionalProperties": false
                  },
                  "linkAdditionOffer": {
                    "required": [
                      "pricingOptions"
                    ],
                    "properties": {
                      "pricingOptions": {
                        "type": "array",
                        "items": {
                          "required": [
                            "linkType",
                            "fee"
                          ],
                          "properties": {
                            "linkType": {
                              "type": "string",
                              "enum": [
                                "dofollow",
                                "nofollow",
                                "citation"
                              ]
                            },
                            "fee": {
                              "description": "Your base fee for adding a link of this type.",
                              "allOf": [
                                {
                                  "$ref": "#/components/schemas/Money"
                                }
                              ]
                            }
                          },
                          "type": "object"
                        }
                      }
                    },
                    "type": "object",
                    "nullable": true,
                    "additionalProperties": false
                  },
                  "extraServices": {
                    "type": "array",
                    "items": {
                      "required": [
                        "name",
                        "cost"
                      ],
                      "properties": {
                        "name": {
                          "type": "string",
                          "enum": [
                            "list_on_homepage",
                            "extra_charge_for_sensitive_topic"
                          ]
                        },
                        "cost": {
                          "description": "What you are paid for the extra service.",
                          "allOf": [
                            {
                              "$ref": "#/components/schemas/Money"
                            }
                          ]
                        }
                      },
                      "type": "object"
                    }
                  }
                },
                "type": "object",
                "additionalProperties": false
              },
              "example": {
                "postOffer": {
                  "pricingOptions": [
                    {
                      "linkType": "dofollow",
                      "feeWhenSellerWritesPost": {
                        "amount": 12000,
                        "currency": "EUR"
                      },
                      "feeWhenSellerDoesNotWritePost": {
                        "amount": 10000,
                        "currency": "EUR"
                      }
                    },
                    {
                      "linkType": "nofollow",
                      "feeWhenSellerWritesPost": {
                        "amount": 9000,
                        "currency": "EUR"
                      },
                      "feeWhenSellerDoesNotWritePost": {
                        "amount": 7000,
                        "currency": "EUR"
                      }
                    }
                  ]
                },
                "linkAdditionOffer": null,
                "extraServices": [
                  {
                    "name": "list_on_homepage",
                    "cost": {
                      "amount": 5000,
                      "currency": "EUR"
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The media, with the fees saved.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SellerMedia"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The key is read-only (code `insufficient_capability`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "The `Idempotency-Key` conflicts (codes `idempotency_key_reused`, `idempotency_request_in_progress`, `idempotency_outcome_unknown`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "The body is not valid (code `validation_failed`): `details.fields` names each field by its path in the body, such as `postOffer.pricingOptions.0.feeWhenSellerWritesPost`, with the rule the media edit page applies. Nothing changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/seller/medias": {
      "get": {
        "tags": [
          "Seller medias"
        ],
        "summary": "List the medias you sell on",
        "description": "Your medias in every state, with your fees and how they perform, newest first by default.",
        "operationId": "listSellerMedias",
        "parameters": [
          {
            "name": "state",
            "in": "query",
            "description": "Only the medias in one of these states, comma-separated: `analyzing`, `pending_review`, `active`, `deactivated`. An unknown state is refused with 422.",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "active,deactivated"
          },
          {
            "name": "sort",
            "in": "query",
            "description": "By creation date, number of published orders or publication rate; a leading `-` sorts descending. Medias with no publication rate come first ascending, last descending. Ties come in id order.",
            "required": false,
            "schema": {
              "type": "string",
              "default": "-createdAt",
              "enum": [
                "-createdAt",
                "createdAt",
                "-numPublishedOrders",
                "numPublishedOrders",
                "-publicationRate",
                "publicationRate"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Medias per page, 1 to 100.",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 20,
              "maximum": 100,
              "minimum": 1
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Medias to skip.",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 0,
              "minimum": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of your medias and how many match in all.",
            "content": {
              "application/json": {
                "schema": {
                  "required": [
                    "items",
                    "total"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/SellerMedia"
                      }
                    },
                    "total": {
                      "type": "integer"
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/wallets/seller/transactions/{id}/document": {
      "get": {
        "tags": [
          "Seller money"
        ],
        "summary": "Download the document of a seller wallet movement",
        "description": "The document Growwer attached to a movement of your seller wallet. 404 when the movement has none (`hasDocument` is false) or the file cannot be read.",
        "operationId": "downloadSellerTransactionDocument",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The document, with its own content type and name.",
            "content": {
              "application/octet-stream": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/withdrawals/{id}/invoice": {
      "get": {
        "tags": [
          "Seller money"
        ],
        "summary": "Download the invoice of a withdrawal",
        "description": "The invoice you uploaded for one of your withdrawals, named `withdrawal-{id}-invoice.pdf`. 404 when the withdrawal has none (`hasInvoice` is false); 503 `storage_unavailable` when the file cannot be read right now.",
        "operationId": "downloadWithdrawalInvoice",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The invoice file.",
            "content": {
              "application/octet-stream": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/wallets/seller": {
      "get": {
        "tags": [
          "Seller money"
        ],
        "summary": "Get your seller wallet",
        "description": "What your sales have earned: the balance you can withdraw now and what is held until orders settle. `restricted` is true while your seller account is restricted; the reason is not published here, and support can tell you more.",
        "operationId": "getSellerWallet",
        "responses": {
          "200": {
            "description": "Your seller wallet.",
            "content": {
              "application/json": {
                "schema": {
                  "required": [
                    "balance",
                    "restricted"
                  ],
                  "properties": {
                    "balance": {
                      "$ref": "#/components/schemas/Balance"
                    },
                    "restricted": {
                      "description": "Whether your seller account is restricted.",
                      "type": "boolean"
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/wallets/seller/transactions": {
      "get": {
        "tags": [
          "Seller money"
        ],
        "summary": "List your seller wallet movements",
        "description": "Every movement of your seller wallet, newest first: earnings from orders, withdrawals and manual corrections. An earning names its order (`orderId`) and a withdrawal its request (`withdrawalId`).",
        "operationId": "listSellerTransactions",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "description": "Movements per page, 1 to 100.",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 20,
              "maximum": 100,
              "minimum": 1
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Movements to skip.",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 0,
              "minimum": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of your movements and how many there are in all.",
            "content": {
              "application/json": {
                "schema": {
                  "required": [
                    "items",
                    "total"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/SellerTransaction"
                      }
                    },
                    "total": {
                      "type": "integer"
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/withdrawals": {
      "get": {
        "tags": [
          "Seller money"
        ],
        "summary": "List your withdrawals",
        "description": "The withdrawals you requested from your seller wallet, newest first. Requesting a withdrawal is not available through the API; use the seller wallet page.",
        "operationId": "listWithdrawals",
        "parameters": [
          {
            "name": "state",
            "in": "query",
            "description": "Only the withdrawals in one of these states, comma-separated: `started`, `approved`, `rejected`. An unknown state is refused with 422.",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "started"
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Withdrawals per page, 1 to 100.",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 20,
              "maximum": 100,
              "minimum": 1
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Withdrawals to skip.",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 0,
              "minimum": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of your withdrawals and how many match in all.",
            "content": {
              "application/json": {
                "schema": {
                  "required": [
                    "items",
                    "total"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Withdrawal"
                      }
                    },
                    "total": {
                      "type": "integer"
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/seller/orders/{id}/accept": {
      "post": {
        "tags": [
          "Seller orders"
        ],
        "summary": "Accept an order",
        "description": "Accepts an order placed on one of your medias (`state` `pending_acceptance`), as the web does. A post order whose draft is still to be written (by you or by Growwer) moves to `pending_draft`; any other order moves to `pending_order_delivery`. The buyer is told. Takes no body.",
        "operationId": "acceptSellerOrder",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "The order, accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SellerOrder"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The key is read-only (code `insufficient_capability`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "The order is not waiting for your acceptance (code `invalid_state`), your seller account is restricted and accepts no orders (code `seller_restricted`; support can tell you why), or the `Idempotency-Key` conflicts (codes `idempotency_key_reused`, `idempotency_request_in_progress`, `idempotency_outcome_unknown`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/seller/orders/{id}/deliver": {
      "post": {
        "tags": [
          "Seller orders"
        ],
        "summary": "Deliver an order",
        "description": "Delivers an order placed on one of your medias (`state` `pending_order_delivery`), as the web does. A post order takes the URL of the published post and the confirmation of its publication date; a link addition order takes no body, and any field is refused. The order moves to `pending_order_delivery_review` and the buyer is asked to review it, or, for a post order whose scheduled publication date is still to come, to `scheduled` without telling the buyer yet. The URL is checked to be a URL only, as the web does.",
        "operationId": "deliverSellerOrder",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SellerOrderPostDelivery"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The order, delivered or scheduled.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SellerOrder"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The key is read-only (code `insufficient_capability`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "The order is not waiting for its delivery (code `invalid_state`), or the `Idempotency-Key` conflicts (codes `idempotency_key_reused`, `idempotency_request_in_progress`, `idempotency_outcome_unknown`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/seller/orders/{id}/deliver-draft": {
      "post": {
        "tags": [
          "Seller orders"
        ],
        "summary": "Deliver a draft",
        "description": "Delivers the draft of a post order placed on one of your medias whose draft you write (`state` `pending_draft`), as the web does, from a file you uploaded with POST /files. The order moves to `pending_draft_review` when the buyer reviews drafts, otherwise to `pending_order_delivery`. The file is used up once the draft is delivered; a refused request leaves it usable.",
        "operationId": "deliverSellerOrderDraft",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SellerOrderDraftFile"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The order, with its draft delivered.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SellerOrder"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The key is read-only (code `insufficient_capability`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "The order is not waiting for a draft you write (code `invalid_state`), or the `Idempotency-Key` conflicts (codes `idempotency_key_reused`, `idempotency_request_in_progress`, `idempotency_outcome_unknown`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "The body is not valid, or the file is not an odt, doc, docx or txt file of up to 8 MB (code `validation_failed`, with the messages of each field in `details.fields`), or `fileId` names no file you can use: it does not exist, has expired or was already used (code `file_unusable`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/seller/orders/{id}/deliver-draft-update": {
      "post": {
        "tags": [
          "Seller orders"
        ],
        "summary": "Deliver a draft update",
        "description": "Delivers the draft update the buyer asked for on a post order placed on one of your medias whose draft you write (`state` `pending_draft_update`), as the web does, from a file you uploaded with POST /files. The order moves back to `pending_draft_review`. The file is used up once the draft is delivered; a refused request leaves it usable.",
        "operationId": "deliverSellerOrderDraftUpdate",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SellerOrderDraftFile"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The order, with its updated draft delivered.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SellerOrder"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The key is read-only (code `insufficient_capability`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "The buyer has not asked for an update of a draft you write (code `invalid_state`), or the `Idempotency-Key` conflicts (codes `idempotency_key_reused`, `idempotency_request_in_progress`, `idempotency_outcome_unknown`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "The body is not valid, or the file is not an odt, doc, docx or txt file of up to 8 MB (code `validation_failed`, with the messages of each field in `details.fields`), or `fileId` names no file you can use: it does not exist, has expired or was already used (code `file_unusable`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/seller/orders/{id}/deliver-update": {
      "post": {
        "tags": [
          "Seller orders"
        ],
        "summary": "Deliver an update",
        "description": "Delivers the update the buyer asked for on an order placed on one of your medias (`state` `pending_order_delivery_update`), as the web does. A post order takes the URL of the published post, which may be the same as before, and the confirmation of its publication date; both must be sent. A link addition order takes no body, and any field is refused. The order moves back to `pending_order_delivery_review` and the buyer is asked to review it.",
        "operationId": "deliverSellerOrderUpdate",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SellerOrderPostDelivery"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The order, with the update delivered.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SellerOrder"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The key is read-only (code `insufficient_capability`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "The buyer has not asked for an update (code `invalid_state`), or the `Idempotency-Key` conflicts (codes `idempotency_key_reused`, `idempotency_request_in_progress`, `idempotency_outcome_unknown`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/seller/orders/{id}/briefing": {
      "get": {
        "tags": [
          "Seller orders"
        ],
        "summary": "Download the draft the buyer attached to an order",
        "description": "The file the buyer attached to the briefing of a post order you sell. 404 when the order has none (`briefing.hasProposedDraft` is false) or the file cannot be read.",
        "operationId": "downloadSellerOrderBriefing",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The file, with its own content type and name.",
            "content": {
              "application/octet-stream": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/seller/orders/{id}/draft": {
      "get": {
        "tags": [
          "Seller orders"
        ],
        "summary": "Download the draft of an order you sell",
        "description": "The file of the current draft of a post order you sell. 404 when the order has no draft file (`draft.hasFile` is false) or the file cannot be read. Earlier drafts are not available.",
        "operationId": "downloadSellerOrderDraft",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The file, with its own content type and name.",
            "content": {
              "application/octet-stream": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/seller/orders/{id}": {
      "get": {
        "tags": [
          "Seller orders"
        ],
        "summary": "Get an order you sell",
        "description": "One order placed on one of your medias, with its briefing, its draft and its state history. An order you only bought is not found here; it is under GET /orders/{id}.",
        "operationId": "getSellerOrder",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The order.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SellerOrder"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/seller/orders": {
      "get": {
        "tags": [
          "Seller orders"
        ],
        "summary": "List the orders you sell",
        "description": "The orders placed on your medias, newest first by default. To follow them, poll with `sort=updatedAt` and `updatedSince` set to the `updatedAt` of the last order you saw: an order moves to the end of that list each time it changes state. The orders you bought are under GET /orders.",
        "operationId": "listSellerOrders",
        "parameters": [
          {
            "name": "mediaId",
            "in": "query",
            "description": "Only the orders on this media of yours.",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "state",
            "in": "query",
            "description": "Only the orders in one of these states, comma-separated. An unknown state is refused with 422 and the list of valid ones.",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "pending_acceptance,pending_order_delivery"
          },
          {
            "name": "updatedSince",
            "in": "query",
            "description": "Only the orders whose `updatedAt` is at or after this instant, an ISO-8601 date-time with its offset (send `+` as `%2B`).",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "`-createdAt`, newest first, or `updatedAt`, least recently changed first. Orders of the same instant come in id order.",
            "required": false,
            "schema": {
              "type": "string",
              "default": "-createdAt",
              "enum": [
                "-createdAt",
                "updatedAt"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Orders per page, 1 to 100.",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 20,
              "maximum": 100,
              "minimum": 1
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Orders to skip.",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 0,
              "minimum": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the orders you sell and how many match in all.",
            "content": {
              "application/json": {
                "schema": {
                  "required": [
                    "items",
                    "total"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/SellerOrder"
                      }
                    },
                    "total": {
                      "type": "integer"
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/seller/orders/{id}/refute-draft-update": {
      "post": {
        "tags": [
          "Seller orders"
        ],
        "summary": "Refuse a draft update",
        "description": "Refuses the draft update the buyer asked for on a post order placed on one of your medias whose draft you write (`state` `pending_draft_update`), as the web does. The order moves back to `pending_draft_review` and the buyer is told your reason. A draft Growwer or the buyer writes cannot be refused here.",
        "operationId": "refuteSellerOrderDraftUpdate",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SellerOrderRefutation"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The order, with its draft back in review.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SellerOrder"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The key is read-only (code `insufficient_capability`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "The buyer has not asked for an update of a draft you write, including when Growwer or the buyer writes the draft (code `invalid_state`), or the `Idempotency-Key` conflicts (codes `idempotency_key_reused`, `idempotency_request_in_progress`, `idempotency_outcome_unknown`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/seller/orders/{id}/refute-update": {
      "post": {
        "tags": [
          "Seller orders"
        ],
        "summary": "Refuse an update",
        "description": "Refuses the update the buyer asked for on an order placed on one of your medias (`state` `pending_order_delivery_update`), as the web does. The order moves back to `pending_order_delivery_review` and the buyer is told your reason.",
        "operationId": "refuteSellerOrderUpdate",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SellerOrderRefutation"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The order, back in review.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SellerOrder"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The key is read-only (code `insufficient_capability`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "The buyer has not asked for an update (code `invalid_state`), or the `Idempotency-Key` conflicts (codes `idempotency_key_reused`, `idempotency_request_in_progress`, `idempotency_outcome_unknown`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/seller/orders/{id}/reject": {
      "post": {
        "tags": [
          "Seller orders"
        ],
        "summary": "Reject an order",
        "description": "Rejects an order placed on one of your medias that you have not accepted yet (`state` `pending_acceptance`), as the web does. The order moves to `rejected_by_seller`, its price returns to the buyer, and the buyer is told your reason.",
        "operationId": "rejectSellerOrder",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SellerOrderRejection"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The order, rejected.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SellerOrder"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The key is read-only (code `insufficient_capability`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "The order is not waiting for your acceptance (code `invalid_state`), or the `Idempotency-Key` conflicts (codes `idempotency_key_reused`, `idempotency_request_in_progress`, `idempotency_outcome_unknown`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/wallets/buyer/transactions/{id}/document": {
      "get": {
        "tags": [
          "Buyer money"
        ],
        "summary": "Download the document of a wallet movement",
        "description": "The document Growwer attached to a movement of your buyer wallet. 404 when the movement has none (`hasDocument` is false) or the file cannot be read.",
        "operationId": "downloadBuyerTransactionDocument",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The document, with its own content type and name.",
            "content": {
              "application/octet-stream": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/wallets/buyer": {
      "get": {
        "tags": [
          "Buyer money"
        ],
        "summary": "Get your buyer wallet",
        "description": "The balance you buy with, and the page where you top it up.",
        "operationId": "getBuyerWallet",
        "responses": {
          "200": {
            "description": "Your buyer wallet.",
            "content": {
              "application/json": {
                "schema": {
                  "required": [
                    "balance",
                    "topUpUrl"
                  ],
                  "properties": {
                    "balance": {
                      "$ref": "#/components/schemas/Balance"
                    },
                    "topUpUrl": {
                      "description": "The wallet page, in your language (English when the web is not available in it), where you top up your balance.",
                      "type": "string",
                      "format": "uri"
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/v1/wallets/buyer/transactions": {
      "get": {
        "tags": [
          "Buyer money"
        ],
        "summary": "List your buyer wallet movements",
        "description": "Every movement of your buyer wallet, newest first: top-ups, order debits and their refunds, gifts and manual corrections.",
        "operationId": "listBuyerTransactions",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "description": "Movements per page, 1 to 100.",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 20,
              "maximum": 100,
              "minimum": 1
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Movements to skip.",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 0,
              "minimum": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of your movements and how many there are in all.",
            "content": {
              "application/json": {
                "schema": {
                  "required": [
                    "items",
                    "total"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Transaction"
                      }
                    },
                    "total": {
                      "type": "integer"
                    }
                  },
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Error": {
        "required": [
          "code",
          "message",
          "requestId"
        ],
        "properties": {
          "code": {
            "description": "A stable, machine-readable error code.",
            "type": "string",
            "example": "unauthorized"
          },
          "message": {
            "description": "A human-readable explanation. It may change.",
            "type": "string"
          },
          "requestId": {
            "description": "The X-Request-Id of the call. Quote it when reporting a problem.",
            "type": "string"
          },
          "details": {
            "description": "Extra data on some errors, such as the invalid fields of a validation_failed error.",
            "type": "object",
            "additionalProperties": true
          }
        },
        "type": "object"
      },
      "Money": {
        "required": [
          "amount",
          "currency"
        ],
        "properties": {
          "amount": {
            "description": "Integer cents.",
            "type": "integer",
            "example": 12500
          },
          "currency": {
            "description": "ISO 4217 currency code.",
            "type": "string",
            "example": "EUR"
          }
        },
        "type": "object"
      },
      "CodeName": {
        "required": [
          "code",
          "name"
        ],
        "properties": {
          "code": {
            "type": "string"
          },
          "name": {
            "type": "string"
          }
        },
        "type": "object"
      },
      "Balance": {
        "required": [
          "available",
          "pending"
        ],
        "properties": {
          "available": {
            "description": "What can be spent, or withdrawn, now.",
            "allOf": [
              {
                "$ref": "#/components/schemas/Money"
              }
            ]
          },
          "pending": {
            "description": "What is held until orders in progress settle.",
            "allOf": [
              {
                "$ref": "#/components/schemas/Money"
              }
            ]
          }
        },
        "type": "object"
      },
      "Project": {
        "required": [
          "id",
          "name",
          "rootUrl",
          "websiteType",
          "topics",
          "language",
          "country",
          "promotedProducts",
          "userKeywords",
          "state",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "description": "Your name for the project, or null when it has none.",
            "type": "string",
            "nullable": true
          },
          "rootUrl": {
            "description": "The website the project promotes. It cannot be changed once the project exists.",
            "type": "string",
            "format": "uri"
          },
          "websiteType": {
            "description": "What the website is: an online shop (`ecommerce`), a services business (`services`) or anything else (`other`).",
            "type": "string",
            "enum": [
              "ecommerce",
              "services",
              "other"
            ]
          },
          "topics": {
            "description": "The website's topic, as a topic id from GET /vocabulary. Exactly one.",
            "type": "array",
            "items": {
              "type": "integer"
            }
          },
          "language": {
            "description": "The language of the campaign, as a language code from GET /vocabulary.",
            "type": "string",
            "example": "es"
          },
          "country": {
            "description": "The country the campaign targets, as a country code from GET /vocabulary, or null for worldwide.",
            "type": "string",
            "example": "ES",
            "nullable": true
          },
          "promotedProducts": {
            "description": "The products or services the campaign promotes, 5 to 10.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "userKeywords": {
            "description": "Keywords you want the campaign to target, at most 100.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "state": {
            "description": "`finished` once Growwer has recommended media for the project, `analyzing`\nuntil then. Analysis can take hours, and it never finishes when no medium\nmatches the project. Poll with backoff, and use `createdAt` to decide how\nlong to keep polling.\n",
            "type": "string",
            "enum": [
              "analyzing",
              "finished"
            ]
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "type": "object"
      },
      "MoneyOrNull": {
        "required": [
          "amount",
          "currency"
        ],
        "properties": {
          "amount": {
            "description": "Integer cents.",
            "type": "integer",
            "example": 12500
          },
          "currency": {
            "description": "ISO 4217 currency code.",
            "type": "string",
            "example": "EUR"
          }
        },
        "type": "object",
        "nullable": true
      },
      "CatalogueOffer": {
        "required": [
          "price",
          "linkType",
          "prices",
          "previousPrice"
        ],
        "properties": {
          "price": {
            "description": "What you pay for the offer with its dearest link type, flash offer discount included.",
            "allOf": [
              {
                "$ref": "#/components/schemas/Money"
              }
            ]
          },
          "linkType": {
            "description": "The link type `price` is for.",
            "type": "string",
            "nullable": true,
            "enum": [
              "dofollow",
              "nofollow",
              "citation",
              null
            ]
          },
          "prices": {
            "description": "What you pay for each link type the offer gives, by link type.",
            "type": "object",
            "additionalProperties": {
              "$ref": "#/components/schemas/Money"
            }
          },
          "previousPrice": {
            "description": "The highest price the offer has had, when `price` is more than 5% below it; otherwise null.",
            "allOf": [
              {
                "$ref": "#/components/schemas/MoneyOrNull"
              }
            ]
          }
        },
        "type": "object"
      },
      "CatalogueOfferOrNull": {
        "required": [
          "price",
          "linkType",
          "prices",
          "previousPrice"
        ],
        "properties": {
          "price": {
            "description": "What you pay for the offer with its dearest link type, flash offer discount included.",
            "allOf": [
              {
                "$ref": "#/components/schemas/Money"
              }
            ]
          },
          "linkType": {
            "description": "The link type `price` is for.",
            "type": "string",
            "nullable": true,
            "enum": [
              "dofollow",
              "nofollow",
              "citation",
              null
            ]
          },
          "prices": {
            "description": "What you pay for each link type the offer gives, by link type.",
            "type": "object",
            "additionalProperties": {
              "$ref": "#/components/schemas/Money"
            }
          },
          "previousPrice": {
            "description": "The highest price the offer has had, when `price` is more than 5% below it; otherwise null.",
            "allOf": [
              {
                "$ref": "#/components/schemas/MoneyOrNull"
              }
            ]
          }
        },
        "type": "object",
        "nullable": true
      },
      "CataloguePostOffer": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CatalogueOffer"
          },
          {
            "required": [
              "advertisingLabel",
              "promotedSocialNetworks",
              "extras"
            ],
            "properties": {
              "advertisingLabel": {
                "description": "Whether the media always labels posts as advertising.",
                "type": "boolean"
              },
              "promotedSocialNetworks": {
                "description": "Where the media promotes the post.",
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "twitter",
                    "instagram",
                    "facebook",
                    "pinterest",
                    "tumblr",
                    "newsletter"
                  ]
                }
              },
              "extras": {
                "required": [
                  "homepageListing",
                  "sensitiveTopic"
                ],
                "properties": {
                  "homepageListing": {
                    "description": "What listing the post on the homepage costs, or null when the media does not offer it.",
                    "allOf": [
                      {
                        "$ref": "#/components/schemas/MoneyOrNull"
                      }
                    ]
                  },
                  "sensitiveTopic": {
                    "required": [
                      "allowed",
                      "extraPrice"
                    ],
                    "properties": {
                      "allowed": {
                        "description": "Whether the media publishes on sensitive topics.",
                        "type": "boolean"
                      },
                      "extraPrice": {
                        "description": "What a post on a sensitive topic costs on top, or null when it costs nothing more.",
                        "allOf": [
                          {
                            "$ref": "#/components/schemas/MoneyOrNull"
                          }
                        ]
                      }
                    },
                    "type": "object"
                  }
                },
                "type": "object"
              }
            },
            "type": "object"
          }
        ]
      },
      "CatalogueMedia": {
        "required": [
          "id",
          "domain",
          "type",
          "language",
          "country",
          "topics",
          "metrics",
          "positiveTrafficTrend",
          "bestSeller",
          "publicationRate",
          "averageDaysToPublication",
          "onHoliday",
          "flashOffer",
          "postOffer",
          "linkAdditionOffer"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "domain": {
            "type": "string",
            "example": "example.com"
          },
          "type": {
            "type": "string",
            "enum": [
              "blog",
              "press"
            ]
          },
          "language": {
            "description": "A language code, as in GET /vocabulary.",
            "type": "string"
          },
          "country": {
            "description": "A country code, as in GET /vocabulary, or null for none.",
            "type": "string",
            "nullable": true
          },
          "topics": {
            "description": "Topic ids, as in GET /vocabulary.",
            "type": "array",
            "items": {
              "type": "integer"
            }
          },
          "metrics": {
            "description": "The latest measurements; each is null until it is first measured.",
            "required": [
              "organicTraffic",
              "domainRating",
              "referringDomains",
              "linkedDomains",
              "linkedToReferringRatio"
            ],
            "properties": {
              "organicTraffic": {
                "description": "Monthly organic traffic.",
                "type": "number",
                "nullable": true
              },
              "domainRating": {
                "type": "number",
                "nullable": true
              },
              "referringDomains": {
                "type": "number",
                "nullable": true
              },
              "linkedDomains": {
                "type": "number",
                "nullable": true
              },
              "linkedToReferringRatio": {
                "type": "number",
                "nullable": true
              }
            },
            "type": "object"
          },
          "positiveTrafficTrend": {
            "type": "boolean"
          },
          "bestSeller": {
            "type": "boolean"
          },
          "publicationRate": {
            "description": "The share of the media's orders that were published, in percent, or null without orders.",
            "type": "integer",
            "nullable": true
          },
          "averageDaysToPublication": {
            "description": "The average days from order to publication, or null without published orders.",
            "type": "integer",
            "nullable": true
          },
          "onHoliday": {
            "description": "Whether the media is on holiday and will take longer to publish.",
            "type": "boolean"
          },
          "flashOffer": {
            "description": "The flash offer running, or null. Its discount is already in the prices.",
            "required": [
              "discountPercent",
              "endsAt"
            ],
            "properties": {
              "discountPercent": {
                "type": "integer"
              },
              "endsAt": {
                "type": "string",
                "format": "date-time"
              }
            },
            "type": "object",
            "nullable": true
          },
          "postOffer": {
            "$ref": "#/components/schemas/CataloguePostOffer"
          },
          "linkAdditionOffer": {
            "description": "Adding a link to an existing article, or null when the media does not offer it.",
            "allOf": [
              {
                "$ref": "#/components/schemas/CatalogueOfferOrNull"
              }
            ]
          }
        },
        "type": "object"
      },
      "ProjectCatalogueMedia": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CatalogueMedia"
          },
          {
            "required": [
              "project"
            ],
            "properties": {
              "project": {
                "description": "The media's state in the project.",
                "required": [
                  "favourite",
                  "discarded",
                  "requested",
                  "recommended",
                  "bought",
                  "new"
                ],
                "properties": {
                  "favourite": {
                    "type": "boolean"
                  },
                  "discarded": {
                    "type": "boolean"
                  },
                  "requested": {
                    "type": "boolean"
                  },
                  "recommended": {
                    "description": "Growwer recommends the media for the project.",
                    "type": "boolean"
                  },
                  "bought": {
                    "description": "You have ordered on the media for the project.",
                    "type": "boolean"
                  },
                  "new": {
                    "description": "Growwer matched the media with the project recently.",
                    "type": "boolean"
                  }
                },
                "type": "object"
              }
            },
            "type": "object"
          }
        ]
      },
      "SellerFees": {
        "required": [
          "feeWhenSellerWritesPost",
          "feeWhenSellerDoesNotWritePost"
        ],
        "properties": {
          "feeWhenSellerWritesPost": {
            "description": "What you are paid for a post you write, or null when you do not offer it.",
            "allOf": [
              {
                "$ref": "#/components/schemas/MoneyOrNull"
              }
            ]
          },
          "feeWhenSellerDoesNotWritePost": {
            "description": "What you are paid for a post the buyer or Growwer writes, or null when you do not offer it.",
            "allOf": [
              {
                "$ref": "#/components/schemas/MoneyOrNull"
              }
            ]
          }
        },
        "type": "object"
      },
      "SellerFeesOrNull": {
        "required": [
          "feeWhenSellerWritesPost",
          "feeWhenSellerDoesNotWritePost"
        ],
        "properties": {
          "feeWhenSellerWritesPost": {
            "description": "What you are paid for a post you write, or null when you do not offer it.",
            "allOf": [
              {
                "$ref": "#/components/schemas/MoneyOrNull"
              }
            ]
          },
          "feeWhenSellerDoesNotWritePost": {
            "description": "What you are paid for a post the buyer or Growwer writes, or null when you do not offer it.",
            "allOf": [
              {
                "$ref": "#/components/schemas/MoneyOrNull"
              }
            ]
          }
        },
        "type": "object",
        "nullable": true
      },
      "SellerMedia": {
        "description": "One of your medias, as its seller sees it.",
        "required": [
          "id",
          "domain",
          "url",
          "state",
          "deactivationStrikes",
          "country",
          "language",
          "topics",
          "bannedTopics",
          "providerComments",
          "publicationRate",
          "averageDaysToPublication",
          "numPublishedOrders",
          "onHoliday",
          "flashOffer",
          "postOffer",
          "linkAdditionOffer",
          "competitiveFees",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "domain": {
            "type": "string",
            "example": "example.com"
          },
          "url": {
            "description": "The media's root URL.",
            "type": "string"
          },
          "state": {
            "type": "string",
            "enum": [
              "analyzing",
              "pending_review",
              "active",
              "deactivated"
            ]
          },
          "deactivationStrikes": {
            "description": "How many times the media was deactivated for not publishing.",
            "type": "integer"
          },
          "country": {
            "description": "A country code, as in GET /vocabulary, or null for none.",
            "type": "string",
            "nullable": true
          },
          "language": {
            "description": "A language code, as in GET /vocabulary.",
            "type": "string"
          },
          "topics": {
            "description": "Topic ids, as in GET /vocabulary.",
            "type": "array",
            "items": {
              "type": "integer"
            }
          },
          "bannedTopics": {
            "description": "The topic ids the media refuses, as in GET /vocabulary.",
            "type": "array",
            "items": {
              "type": "integer"
            }
          },
          "providerComments": {
            "description": "Your notes for buyers, or null for none.",
            "type": "string",
            "nullable": true
          },
          "publicationRate": {
            "description": "The share of the media's orders that were published, in percent, or null without orders.",
            "type": "integer",
            "nullable": true
          },
          "averageDaysToPublication": {
            "description": "The average days from order to publication, or null without published orders.",
            "type": "integer",
            "nullable": true
          },
          "numPublishedOrders": {
            "type": "integer"
          },
          "onHoliday": {
            "type": "boolean"
          },
          "flashOffer": {
            "description": "The flash offer running, or null. Its discount is in `currentCost`, never in the fees.",
            "required": [
              "discountPercent",
              "endsAt"
            ],
            "properties": {
              "discountPercent": {
                "type": "integer"
              },
              "endsAt": {
                "type": "string",
                "format": "date-time"
              }
            },
            "type": "object",
            "nullable": true
          },
          "postOffer": {
            "required": [
              "pricingOptions",
              "extraServices"
            ],
            "properties": {
              "pricingOptions": {
                "description": "One entry per link type you offer.",
                "type": "array",
                "items": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/SellerFees"
                    },
                    {
                      "required": [
                        "linkType",
                        "currentCost"
                      ],
                      "properties": {
                        "linkType": {
                          "type": "string",
                          "enum": [
                            "dofollow",
                            "nofollow",
                            "citation"
                          ]
                        },
                        "currentCost": {
                          "description": "What you are paid now for the link type, flash offer discount included; read-only. Null when the link type has no current pricing.",
                          "allOf": [
                            {
                              "$ref": "#/components/schemas/MoneyOrNull"
                            }
                          ]
                        }
                      },
                      "type": "object"
                    }
                  ]
                }
              },
              "extraServices": {
                "type": "array",
                "items": {
                  "required": [
                    "name",
                    "cost"
                  ],
                  "properties": {
                    "name": {
                      "type": "string",
                      "enum": [
                        "list_on_homepage",
                        "extra_charge_for_sensitive_topic"
                      ]
                    },
                    "cost": {
                      "description": "What you are paid for the extra service.",
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/Money"
                        }
                      ]
                    }
                  },
                  "type": "object"
                }
              }
            },
            "type": "object"
          },
          "linkAdditionOffer": {
            "description": "Adding a link to an existing article, or null when you do not offer it.",
            "required": [
              "pricingOptions"
            ],
            "properties": {
              "pricingOptions": {
                "type": "array",
                "items": {
                  "required": [
                    "linkType",
                    "fee",
                    "currentCost"
                  ],
                  "properties": {
                    "linkType": {
                      "type": "string",
                      "enum": [
                        "dofollow",
                        "nofollow",
                        "citation"
                      ]
                    },
                    "fee": {
                      "description": "Your base fee for the link type.",
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/Money"
                        }
                      ]
                    },
                    "currentCost": {
                      "description": "What you are paid now for the link type, flash offer discount included; read-only.",
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/MoneyOrNull"
                        }
                      ]
                    }
                  },
                  "type": "object"
                }
              }
            },
            "type": "object",
            "nullable": true
          },
          "competitiveFees": {
            "description": "The post fees Growwer suggests to sell more, as the seller media page does, or null when it suggests none. A side Growwer finds no competitive fee for is null: unlike the page, it never shows the fixed fee the page falls back to. POST /seller/medias/{id}/apply-competitive-fees sets them.",
            "allOf": [
              {
                "$ref": "#/components/schemas/SellerFeesOrNull"
              }
            ]
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "type": "object"
      },
      "SavedFilter": {
        "required": [
          "id",
          "name",
          "activeFilterCount",
          "notifications",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "activeFilterCount": {
            "description": "How many filters it applies.",
            "type": "integer"
          },
          "notifications": {
            "required": [
              "enabled",
              "frequency"
            ],
            "properties": {
              "enabled": {
                "type": "boolean"
              },
              "frequency": {
                "description": "How often Growwer emails new matching medias, or null when it does not.",
                "type": "string",
                "nullable": true,
                "enum": [
                  "instant",
                  "daily",
                  "weekly",
                  "monthly",
                  null
                ]
              }
            },
            "type": "object"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "type": "object"
      },
      "OrderLink": {
        "required": [
          "targetUrl",
          "anchor",
          "type"
        ],
        "properties": {
          "targetUrl": {
            "description": "Where the link points, or null for a citation.",
            "type": "string",
            "nullable": true
          },
          "anchor": {
            "description": "The anchor text, or null when the media chooses it. A citation always has one.",
            "type": "string",
            "nullable": true
          },
          "type": {
            "type": "string",
            "enum": [
              "dofollow",
              "nofollow",
              "citation"
            ]
          }
        },
        "type": "object"
      },
      "PostOrderBriefing": {
        "description": "The briefing of a post order (`type` `post`).",
        "required": [
          "title",
          "language",
          "links",
          "extraServices",
          "additionalInfo",
          "hasProposedDraft"
        ],
        "properties": {
          "title": {
            "type": "string",
            "nullable": true
          },
          "language": {
            "description": "The language code of the article.",
            "type": "string"
          },
          "links": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OrderLink"
            }
          },
          "extraServices": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "list_on_homepage",
                "extra_charge_for_sensitive_topic"
              ]
            }
          },
          "additionalInfo": {
            "type": "string",
            "nullable": true
          },
          "hasProposedDraft": {
            "description": "Whether you attached your own draft; GET /orders/{id}/briefing downloads it.",
            "type": "boolean"
          }
        },
        "type": "object"
      },
      "LinkAdditionOrderBriefing": {
        "description": "The briefing of a link addition (`type` `link_addition`).",
        "required": [
          "linkingFrom",
          "link",
          "additionalInfo"
        ],
        "properties": {
          "linkingFrom": {
            "description": "The existing article of the media the link goes into.",
            "type": "string"
          },
          "link": {
            "$ref": "#/components/schemas/OrderLink"
          },
          "additionalInfo": {
            "type": "string",
            "nullable": true
          }
        },
        "type": "object"
      },
      "Order": {
        "required": [
          "id",
          "reference",
          "type",
          "state",
          "pendingAction",
          "price",
          "project",
          "media",
          "createdAt",
          "updatedAt",
          "scheduledPublicationDate",
          "delivery",
          "briefing",
          "draft",
          "stateHistory",
          "channel"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "reference": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "post",
              "link_addition"
            ]
          },
          "state": {
            "description": "The raw state name. GET /orders documents the values its `state` filter takes.",
            "type": "string"
          },
          "pendingAction": {
            "description": "Who the order is waiting on, or null when it waits on no one.",
            "type": "string",
            "nullable": true,
            "enum": [
              "buyer",
              "seller",
              "growwer",
              null
            ]
          },
          "price": {
            "description": "What you pay for the order.",
            "allOf": [
              {
                "$ref": "#/components/schemas/Money"
              }
            ]
          },
          "project": {
            "required": [
              "id",
              "url"
            ],
            "properties": {
              "id": {
                "description": "Null once the project is deleted.",
                "type": "string",
                "format": "uuid",
                "nullable": true
              },
              "url": {
                "description": "The project's URL when the order was placed.",
                "type": "string"
              }
            },
            "type": "object"
          },
          "media": {
            "required": [
              "id",
              "url"
            ],
            "properties": {
              "id": {
                "description": "Null once the media is deleted.",
                "type": "string",
                "format": "uuid",
                "nullable": true
              },
              "url": {
                "description": "The media's URL when the order was placed.",
                "type": "string"
              }
            },
            "type": "object"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "description": "When the order last changed state. It changes on state changes only, so poll with GET /orders?updatedSince= on it.",
            "type": "string",
            "format": "date-time"
          },
          "scheduledPublicationDate": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "delivery": {
            "description": "Where the order was published, once it is.",
            "required": [
              "url",
              "publishedAt"
            ],
            "properties": {
              "url": {
                "description": "The published article, or for a link addition the article the link went into.",
                "type": "string"
              },
              "publishedAt": {
                "description": "When the post was published; null for a link addition.",
                "type": "string",
                "format": "date-time",
                "nullable": true
              }
            },
            "type": "object",
            "nullable": true
          },
          "briefing": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/PostOrderBriefing"
              },
              {
                "$ref": "#/components/schemas/LinkAdditionOrderBriefing"
              }
            ]
          },
          "draft": {
            "description": "The draft of a post order that has one; null otherwise, and always for a link addition.",
            "required": [
              "authoredByBuyer",
              "reviewable",
              "hasFile"
            ],
            "properties": {
              "authoredByBuyer": {
                "description": "Whether you write the draft.",
                "type": "boolean"
              },
              "reviewable": {
                "description": "Whether you review the draft before it is published.",
                "type": "boolean"
              },
              "hasFile": {
                "description": "Whether the current draft has a file; GET /orders/{id}/draft downloads it.",
                "type": "boolean"
              }
            },
            "type": "object",
            "nullable": true
          },
          "stateHistory": {
            "description": "Every state change, oldest first.",
            "type": "array",
            "items": {
              "required": [
                "state",
                "date",
                "reason"
              ],
              "properties": {
                "state": {
                  "type": "string"
                },
                "date": {
                  "type": "string",
                  "format": "date-time"
                },
                "reason": {
                  "required": [
                    "code",
                    "additionalInfo"
                  ],
                  "properties": {
                    "code": {
                      "type": "string",
                      "enum": [
                        "other_reasons",
                        "media_is_competition",
                        "media_has_exclusivity",
                        "forbidden_topic",
                        "no_seller_response",
                        "not_available_media"
                      ]
                    },
                    "additionalInfo": {
                      "type": "string",
                      "nullable": true
                    }
                  },
                  "type": "object",
                  "nullable": true
                }
              },
              "type": "object"
            }
          },
          "channel": {
            "required": [
              "created"
            ],
            "properties": {
              "created": {
                "description": "Whether the order was placed through this API or on the web.",
                "type": "string",
                "enum": [
                  "api",
                  "web"
                ]
              }
            },
            "type": "object"
          }
        },
        "type": "object"
      },
      "SellerPostOrderBriefing": {
        "description": "The briefing of a post order (`type` `post`), as you, the seller, receive it.",
        "required": [
          "title",
          "language",
          "links",
          "extraServices",
          "additionalInfo",
          "writtenBy",
          "hasProposedDraft"
        ],
        "properties": {
          "title": {
            "type": "string",
            "nullable": true
          },
          "language": {
            "description": "The language code of the article.",
            "type": "string"
          },
          "links": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OrderLink"
            }
          },
          "extraServices": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "list_on_homepage",
                "extra_charge_for_sensitive_topic"
              ]
            }
          },
          "additionalInfo": {
            "type": "string",
            "nullable": true
          },
          "writtenBy": {
            "description": "Who writes the article; `seller` means you do.",
            "type": "string",
            "enum": [
              "seller",
              "buyer",
              "growwer"
            ]
          },
          "hasProposedDraft": {
            "description": "Whether the buyer attached a draft; GET /seller/orders/{id}/briefing downloads it.",
            "type": "boolean"
          }
        },
        "type": "object"
      },
      "SellerOrder": {
        "description": "An order placed on one of your medias, as its seller sees it.",
        "required": [
          "id",
          "reference",
          "type",
          "state",
          "requiresYourAction",
          "availableActions",
          "earnings",
          "project",
          "media",
          "createdAt",
          "updatedAt",
          "scheduledPublicationDate",
          "delivery",
          "briefing",
          "draft",
          "stateHistory",
          "channel"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "reference": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "post",
              "link_addition"
            ]
          },
          "state": {
            "description": "The raw state name. GET /seller/orders documents the values its `state` filter takes.",
            "type": "string"
          },
          "requiresYourAction": {
            "description": "Whether the order waits on you, as the seller order list marks it.",
            "type": "boolean"
          },
          "availableActions": {
            "description": "The seller actions the order allows now.",
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "accept",
                "reject",
                "deliver",
                "deliver-update",
                "refute-update",
                "deliver-draft",
                "deliver-draft-update",
                "refute-draft-update"
              ]
            }
          },
          "earnings": {
            "description": "What you are paid for the order, credited to your seller wallet once it settles.",
            "allOf": [
              {
                "$ref": "#/components/schemas/Money"
              }
            ]
          },
          "project": {
            "required": [
              "url"
            ],
            "properties": {
              "url": {
                "description": "The URL the buyer promotes, as recorded when the order was placed.",
                "type": "string"
              }
            },
            "type": "object"
          },
          "media": {
            "required": [
              "id",
              "url"
            ],
            "properties": {
              "id": {
                "description": "Null once the media is deleted.",
                "type": "string",
                "format": "uuid",
                "nullable": true
              },
              "url": {
                "description": "The media's URL when the order was placed.",
                "type": "string"
              }
            },
            "type": "object"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "description": "When the order last changed state. It changes on state changes only, so poll with GET /seller/orders?updatedSince= on it.",
            "type": "string",
            "format": "date-time"
          },
          "scheduledPublicationDate": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "delivery": {
            "description": "Where the order was published, once it is.",
            "required": [
              "url",
              "publishedAt"
            ],
            "properties": {
              "url": {
                "description": "The published article, or for a link addition the article the link went into.",
                "type": "string"
              },
              "publishedAt": {
                "description": "When the post was published; null for a link addition.",
                "type": "string",
                "format": "date-time",
                "nullable": true
              }
            },
            "type": "object",
            "nullable": true
          },
          "briefing": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/SellerPostOrderBriefing"
              },
              {
                "$ref": "#/components/schemas/LinkAdditionOrderBriefing"
              }
            ]
          },
          "draft": {
            "description": "The draft of a post order that has one; null otherwise, and always for a link addition.",
            "required": [
              "reviewable",
              "hasFile"
            ],
            "properties": {
              "reviewable": {
                "description": "Whether the buyer reviews the draft before it is published.",
                "type": "boolean"
              },
              "hasFile": {
                "description": "Whether the current draft has a file; GET /seller/orders/{id}/draft downloads it.",
                "type": "boolean"
              }
            },
            "type": "object",
            "nullable": true
          },
          "stateHistory": {
            "description": "Every state change, oldest first.",
            "type": "array",
            "items": {
              "required": [
                "state",
                "date",
                "reason"
              ],
              "properties": {
                "state": {
                  "type": "string"
                },
                "date": {
                  "type": "string",
                  "format": "date-time"
                },
                "reason": {
                  "required": [
                    "code",
                    "additionalInfo"
                  ],
                  "properties": {
                    "code": {
                      "type": "string",
                      "enum": [
                        "other_reasons",
                        "media_is_competition",
                        "media_has_exclusivity",
                        "forbidden_topic",
                        "no_seller_response",
                        "not_available_media"
                      ]
                    },
                    "additionalInfo": {
                      "type": "string",
                      "nullable": true
                    }
                  },
                  "type": "object",
                  "nullable": true
                }
              },
              "type": "object"
            }
          },
          "channel": {
            "required": [
              "created",
              "accepted"
            ],
            "properties": {
              "created": {
                "description": "Whether the order was placed through this API or on the web.",
                "type": "string",
                "enum": [
                  "api",
                  "web"
                ]
              },
              "accepted": {
                "description": "Whether you accepted the order through this API or elsewhere, or null while it is not accepted.",
                "type": "string",
                "nullable": true,
                "enum": [
                  "api",
                  "web",
                  null
                ]
              }
            },
            "type": "object"
          }
        },
        "type": "object"
      },
      "OrderLinkRequest": {
        "required": [
          "type"
        ],
        "properties": {
          "targetUrl": {
            "description": "Where the link points; leave it out for a citation.",
            "type": "string"
          },
          "anchor": {
            "description": "The anchor text; leave it out to let the media choose it. A citation needs one.",
            "type": "string"
          },
          "type": {
            "description": "A link type the media offers for this type of order (CatalogueOffer `linkTypes`).",
            "type": "string",
            "enum": [
              "dofollow",
              "nofollow",
              "citation"
            ]
          }
        },
        "type": "object"
      },
      "PostOrderBriefingRequest": {
        "description": "The briefing of a post order (`type` `post`), checked against the media's post offer as the web checks it.",
        "required": [
          "links"
        ],
        "properties": {
          "links": {
            "description": "No more links than the offer allows.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OrderLinkRequest"
            }
          },
          "extraServices": {
            "description": "Extra services the offer has, added to the ones the web selects for your project by default. A project with a sensitive topic always carries `extra_charge_for_sensitive_topic` when the media charges it.",
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "list_on_homepage",
                "extra_charge_for_sensitive_topic"
              ]
            }
          },
          "title": {
            "type": "string"
          },
          "additionalInfo": {
            "type": "string"
          }
        },
        "type": "object"
      },
      "LinkAdditionOrderBriefingRequest": {
        "description": "The briefing of a link addition (`type` `link_addition`), checked against the media's link addition offer as the web checks it.",
        "required": [
          "linkingFrom",
          "link"
        ],
        "properties": {
          "linkingFrom": {
            "description": "The URL of an existing article on the media's domain that the link goes into.",
            "type": "string"
          },
          "link": {
            "$ref": "#/components/schemas/OrderLinkRequest"
          },
          "additionalInfo": {
            "type": "string"
          }
        },
        "type": "object"
      },
      "OrderEstimateRequest": {
        "description": "An order to price. `scheduledPublicationDate`, `draftReviewable` and `proposedDraftFileId` apply to a post order only.",
        "required": [
          "type",
          "projectId",
          "mediaId",
          "briefing"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "post",
              "link_addition"
            ]
          },
          "projectId": {
            "description": "One of your projects.",
            "type": "string",
            "format": "uuid"
          },
          "mediaId": {
            "description": "A media you can order for the project (GET /projects/{id}/medias).",
            "type": "string",
            "format": "uuid"
          },
          "briefing": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/PostOrderBriefingRequest"
              },
              {
                "$ref": "#/components/schemas/LinkAdditionOrderBriefingRequest"
              }
            ]
          },
          "scheduledPublicationDate": {
            "description": "The day to publish on, at least a few days ahead as the web requires.",
            "type": "string",
            "format": "date"
          },
          "draftReviewable": {
            "description": "Whether you review the draft before it is published. Defaults to false.",
            "type": "boolean"
          },
          "proposedDraftFileId": {
            "description": "A file uploaded with POST /files to propose your own draft. The estimate checks it without using it up.",
            "type": "string",
            "format": "uuid"
          }
        },
        "type": "object"
      },
      "OrderCreateRequest": {
        "description": "An order to place, with the price you expect to pay.",
        "allOf": [
          {
            "$ref": "#/components/schemas/OrderEstimateRequest"
          },
          {
            "required": [
              "expectedPrice"
            ],
            "properties": {
              "expectedPrice": {
                "description": "The `price` POST /orders/estimate answered. Only EUR is accepted.",
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Money"
                  }
                ]
              }
            },
            "type": "object"
          }
        ]
      },
      "OrderEstimate": {
        "required": [
          "price",
          "availableBalance",
          "missing",
          "sufficientBalance"
        ],
        "properties": {
          "price": {
            "description": "What the order costs you. Send it as `expectedPrice`.",
            "allOf": [
              {
                "$ref": "#/components/schemas/Money"
              }
            ]
          },
          "availableBalance": {
            "description": "Your wallet's available balance.",
            "allOf": [
              {
                "$ref": "#/components/schemas/Money"
              }
            ]
          },
          "missing": {
            "description": "How much the available balance falls short of the price; zero when it covers it.",
            "allOf": [
              {
                "$ref": "#/components/schemas/Money"
              }
            ]
          },
          "sufficientBalance": {
            "description": "Whether the available balance covers the price.",
            "type": "boolean"
          }
        },
        "type": "object"
      },
      "OrderActionReason": {
        "required": [
          "reason"
        ],
        "properties": {
          "reason": {
            "description": "What the seller is told, 10 to 2000 characters once trimmed.",
            "type": "string",
            "maxLength": 2000,
            "minLength": 10
          }
        },
        "type": "object"
      },
      "SellerOrderRefutation": {
        "required": [
          "reason"
        ],
        "properties": {
          "reason": {
            "description": "Why you refuse the buyer's request, which the buyer is told, 10 to 2000 characters once trimmed.",
            "type": "string",
            "maxLength": 2000,
            "minLength": 10
          }
        },
        "type": "object"
      },
      "SellerOrderRejection": {
        "required": [
          "reason"
        ],
        "properties": {
          "reason": {
            "required": [
              "name"
            ],
            "properties": {
              "name": {
                "description": "Why you reject the order, as the seller order page offers it.",
                "type": "string",
                "enum": [
                  "media_is_competition",
                  "media_has_exclusivity",
                  "forbidden_topic",
                  "other_reasons"
                ]
              },
              "additionalInfo": {
                "description": "More about the reason, which the buyer is told, 10 to 2000 characters. Required with `other_reasons`.",
                "type": "string",
                "nullable": true,
                "maxLength": 2000,
                "minLength": 10
              }
            },
            "type": "object"
          }
        },
        "type": "object"
      },
      "SellerOrderPostDelivery": {
        "description": "The published post of a post order. A link addition order takes no body.",
        "required": [
          "url",
          "publicationDateConfirmed"
        ],
        "properties": {
          "url": {
            "description": "The URL of the published post. It is checked to be a URL only, as the web does; whether the post carries the links is not checked here.",
            "type": "string",
            "format": "uri"
          },
          "publicationDateConfirmed": {
            "description": "Must be true. Confirms the post is live, or for an order with a scheduled publication date, that it will be published on that date.",
            "type": "boolean"
          }
        },
        "type": "object"
      },
      "SellerOrderDraftFile": {
        "required": [
          "fileId"
        ],
        "properties": {
          "fileId": {
            "description": "A file you uploaded with POST /files and have not used yet. It must be an odt, doc, docx or txt file of up to 8 MB. It is used up once the draft is delivered.",
            "type": "string",
            "format": "uuid"
          }
        },
        "type": "object"
      },
      "Transaction": {
        "required": [
          "id",
          "type",
          "state",
          "direction",
          "amount",
          "description",
          "descriptionCode",
          "orderId",
          "invoiceId",
          "hasDocument",
          "createdAt",
          "updatedAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "type": {
            "description": "What moved the money, for example `deposit` (a top-up), `debit_from_order` (an order), `gift` or `manual_charge`.",
            "type": "string"
          },
          "state": {
            "description": "An order's debit stays `pending_confirmation` until the order settles, and is `cancelled` when the order is refunded.",
            "type": "string",
            "enum": [
              "pending_confirmation",
              "confirmed",
              "cancelled"
            ]
          },
          "direction": {
            "type": "string",
            "enum": [
              "credit",
              "debit"
            ]
          },
          "amount": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Money"
              }
            ]
          },
          "description": {
            "description": "The text the wallet page prints as it is, or null where it prints a translated label instead (then see `descriptionCode`).",
            "type": "string",
            "nullable": true
          },
          "descriptionCode": {
            "description": "A stable code for the label the wallet page translates: a payment method for a top-up, or `affiliate_promo`. Null otherwise.",
            "type": "string",
            "nullable": true
          },
          "orderId": {
            "description": "The order this transaction paid for or refunded, while it exists.",
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "invoiceId": {
            "description": "The invoice of this transaction, if any; GET /invoices/{id}/pdf downloads it.",
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "hasDocument": {
            "description": "Whether GET /wallets/buyer/transactions/{id}/document downloads a document for it.",
            "type": "boolean"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "type": "object"
      },
      "SellerTransaction": {
        "description": "A movement of your seller wallet.",
        "required": [
          "id",
          "type",
          "state",
          "direction",
          "amount",
          "description",
          "orderId",
          "withdrawalId",
          "hasDocument",
          "createdAt",
          "updatedAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "type": {
            "description": "What moved the money, for example `credit_from_order` (an order you delivered), `credit_from_writing`, `withdrawal`, `manual_deposit` or `manual_charge`.",
            "type": "string"
          },
          "state": {
            "description": "An order's earning stays `pending_confirmation` until the order settles.",
            "type": "string",
            "enum": [
              "pending_confirmation",
              "confirmed",
              "cancelled"
            ]
          },
          "direction": {
            "type": "string",
            "enum": [
              "credit",
              "debit"
            ]
          },
          "amount": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Money"
              }
            ]
          },
          "description": {
            "description": "The text the wallet page prints, or null when the movement points to an order or a withdrawal instead, or has no text.",
            "type": "string",
            "nullable": true
          },
          "orderId": {
            "description": "Your order this earning came from, while it exists; GET /seller/orders/{id} reads it.",
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "withdrawalId": {
            "description": "Your withdrawal this debit paid; GET /withdrawals lists it.",
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "hasDocument": {
            "description": "Whether GET /wallets/seller/transactions/{id}/document downloads a document for it.",
            "type": "boolean"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "type": "object"
      },
      "Withdrawal": {
        "required": [
          "id",
          "state",
          "amount",
          "method",
          "hasInvoice",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "state": {
            "type": "string",
            "enum": [
              "started",
              "approved",
              "rejected"
            ]
          },
          "amount": {
            "description": "What you withdraw.",
            "allOf": [
              {
                "$ref": "#/components/schemas/Money"
              }
            ]
          },
          "method": {
            "type": "string",
            "enum": [
              "bank_transfer",
              "paypal"
            ]
          },
          "hasInvoice": {
            "description": "Whether you uploaded an invoice; GET /withdrawals/{id}/invoice downloads it.",
            "type": "boolean"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "type": "object"
      },
      "Invoice": {
        "required": [
          "id",
          "number",
          "issuedAt",
          "total"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "number": {
            "type": "string"
          },
          "issuedAt": {
            "type": "string",
            "format": "date-time"
          },
          "total": {
            "description": "The invoice total, taxes included.",
            "allOf": [
              {
                "$ref": "#/components/schemas/Money"
              }
            ]
          }
        },
        "type": "object"
      },
      "ManagedServiceCampaign": {
        "description": "A campaign your managed service runs for you. Every figure about proposals counts only those you can see (not the ones the team is still preparing).",
        "required": [
          "id",
          "name",
          "state",
          "deadline",
          "budget",
          "project",
          "strategy",
          "proposalCounts",
          "proposalsTotal",
          "budgetExceededBy",
          "createdAt",
          "updatedAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "state": {
            "description": "`proposal_delivered`: proposals await your review. `proposal_changes_requested`: you rejected some and the team is preparing others. `proposal_accepted`: none awaits your review and the team is placing the orders.",
            "type": "string",
            "enum": [
              "pending_proposal_delivery",
              "proposal_delivered",
              "proposal_changes_requested",
              "proposal_accepted",
              "finished"
            ]
          },
          "deadline": {
            "type": "string",
            "format": "date-time"
          },
          "budget": {
            "$ref": "#/components/schemas/Money"
          },
          "project": {
            "required": [
              "id",
              "url"
            ],
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "url": {
                "type": "string"
              }
            },
            "type": "object",
            "nullable": true
          },
          "strategy": {
            "required": [
              "goal",
              "countries",
              "languages",
              "topics",
              "definition"
            ],
            "properties": {
              "goal": {
                "type": "string",
                "enum": [
                  "link_building",
                  "branding",
                  "reputation",
                  "other"
                ]
              },
              "countries": {
                "description": "ISO 3166-1 alpha-2 codes.",
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "languages": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "topics": {
                "description": "Topic ids, as GET /vocabulary lists them.",
                "type": "array",
                "items": {
                  "type": "integer"
                }
              },
              "definition": {
                "type": "string"
              }
            },
            "type": "object"
          },
          "proposalCounts": {
            "description": "How many of the campaign's proposals are in each state.",
            "required": [
              "proposed",
              "accepted",
              "cancelled",
              "purchase_started",
              "purchase_finished"
            ],
            "properties": {
              "proposed": {
                "type": "integer"
              },
              "accepted": {
                "type": "integer"
              },
              "cancelled": {
                "type": "integer"
              },
              "purchase_started": {
                "type": "integer"
              },
              "purchase_finished": {
                "type": "integer"
              }
            },
            "type": "object"
          },
          "proposalsTotal": {
            "description": "The current price of every proposal not cancelled, as the campaign page totals it.",
            "allOf": [
              {
                "$ref": "#/components/schemas/Money"
              }
            ]
          },
          "budgetExceededBy": {
            "description": "How far `proposalsTotal` goes beyond the budget; null within it.",
            "allOf": [
              {
                "$ref": "#/components/schemas/MoneyOrNull"
              }
            ]
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "description": "When the campaign last changed state.",
            "type": "string",
            "format": "date-time"
          }
        },
        "type": "object"
      },
      "ManagedServiceProposal": {
        "description": "A media the team proposes for a campaign, with the publication it would get.",
        "required": [
          "id",
          "state",
          "media",
          "service",
          "proposedPrice",
          "currentPrice",
          "briefing",
          "stateReason",
          "orderId",
          "orderState",
          "createdAt",
          "updatedAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "state": {
            "description": "`proposed` awaits your review. `accepted` awaits the order the team places for you. `purchase_started` and `purchase_finished` follow that order.",
            "type": "string",
            "enum": [
              "proposed",
              "accepted",
              "cancelled",
              "purchase_started",
              "purchase_finished"
            ]
          },
          "media": {
            "required": [
              "id",
              "domain",
              "language",
              "country"
            ],
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "domain": {
                "type": "string"
              },
              "language": {
                "type": "string",
                "nullable": true
              },
              "country": {
                "type": "string",
                "nullable": true
              }
            },
            "type": "object"
          },
          "service": {
            "type": "string",
            "enum": [
              "post",
              "link_addition"
            ]
          },
          "proposedPrice": {
            "description": "The price the proposal was made at, the one the summary PDF shows.",
            "allOf": [
              {
                "$ref": "#/components/schemas/Money"
              }
            ]
          },
          "currentPrice": {
            "description": "What the media charges for the service today; null when it no longer offers it.",
            "allOf": [
              {
                "$ref": "#/components/schemas/MoneyOrNull"
              }
            ]
          },
          "briefing": {
            "required": [
              "mainInfo",
              "links",
              "additionalInfo",
              "requiresDraft"
            ],
            "properties": {
              "mainInfo": {
                "type": "string"
              },
              "links": {
                "type": "array",
                "items": {
                  "required": [
                    "targetUrl",
                    "anchor",
                    "type"
                  ],
                  "properties": {
                    "targetUrl": {
                      "type": "string",
                      "nullable": true
                    },
                    "anchor": {
                      "type": "string"
                    },
                    "type": {
                      "type": "string",
                      "enum": [
                        "dofollow",
                        "nofollow",
                        "citation"
                      ]
                    }
                  },
                  "type": "object"
                }
              },
              "additionalInfo": {
                "type": "string"
              },
              "requiresDraft": {
                "type": "boolean"
              }
            },
            "type": "object"
          },
          "stateReason": {
            "description": "Why the proposal reached its state, in your language, such as your comment when you rejected it.",
            "type": "string",
            "nullable": true
          },
          "orderId": {
            "description": "The order placed for the proposal (GET /orders/{id}).",
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "orderState": {
            "description": "The state of that order while its purchase is in progress.",
            "type": "string",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "description": "When the proposal last changed state.",
            "type": "string",
            "format": "date-time"
          }
        },
        "type": "object"
      },
      "ManagedServiceProposalReviewRequest": {
        "required": [
          "reviews"
        ],
        "properties": {
          "reviews": {
            "description": "One decision on each proposal of the campaign that is `proposed`, each named once. Their order does not matter.",
            "type": "array",
            "items": {
              "required": [
                "proposalId",
                "decision"
              ],
              "properties": {
                "proposalId": {
                  "type": "string",
                  "format": "uuid"
                },
                "decision": {
                  "type": "string",
                  "enum": [
                    "accept",
                    "reject"
                  ]
                },
                "comment": {
                  "description": "Required to reject, at most 2000 characters once trimmed; the team reads it.",
                  "type": "string",
                  "nullable": true,
                  "maxLength": 2000
                }
              },
              "type": "object"
            },
            "minItems": 1
          }
        },
        "type": "object"
      },
      "ManagedServiceProposalReview": {
        "required": [
          "campaign",
          "proposals"
        ],
        "properties": {
          "campaign": {
            "$ref": "#/components/schemas/ManagedServiceCampaign"
          },
          "proposals": {
            "description": "The proposals you reviewed, newest first.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ManagedServiceProposal"
            }
          }
        },
        "type": "object"
      },
      "ManagedServiceProposalsEstimateRequest": {
        "properties": {
          "accept": {
            "description": "The `proposed` proposals you would accept, each once. Leave it out to price only the accepted ones.",
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            }
          }
        },
        "type": "object"
      },
      "ManagedServiceProposalsEstimate": {
        "required": [
          "acceptedTotal",
          "selectedTotal",
          "total",
          "availableBalance",
          "missing",
          "sufficientBalance"
        ],
        "properties": {
          "acceptedTotal": {
            "description": "The proposals already accepted and still awaiting their order.",
            "allOf": [
              {
                "$ref": "#/components/schemas/Money"
              }
            ]
          },
          "selectedTotal": {
            "description": "The proposals named in `accept`.",
            "allOf": [
              {
                "$ref": "#/components/schemas/Money"
              }
            ]
          },
          "total": {
            "description": "`acceptedTotal` plus `selectedTotal`.",
            "allOf": [
              {
                "$ref": "#/components/schemas/Money"
              }
            ]
          },
          "availableBalance": {
            "description": "Your wallet's available balance.",
            "allOf": [
              {
                "$ref": "#/components/schemas/Money"
              }
            ]
          },
          "missing": {
            "description": "How much the available balance falls short of `total`; zero when it covers it.",
            "allOf": [
              {
                "$ref": "#/components/schemas/Money"
              }
            ]
          },
          "sufficientBalance": {
            "description": "Whether the available balance covers `total`.",
            "type": "boolean"
          }
        },
        "type": "object"
      },
      "ManagedServiceRequest": {
        "required": [
          "projectUrl",
          "goal",
          "country",
          "duration",
          "estimatedBudget"
        ],
        "properties": {
          "projectUrl": {
            "description": "The website the campaign is for.",
            "type": "string"
          },
          "goal": {
            "type": "string",
            "enum": [
              "link_building",
              "branding",
              "reputation",
              "ai_visibility"
            ]
          },
          "country": {
            "description": "ISO 3166-1 alpha-2 code of the target country.",
            "type": "string"
          },
          "duration": {
            "type": "string",
            "enum": [
              "one_time",
              "monthly"
            ]
          },
          "estimatedBudget": {
            "description": "At least 500 EUR. Only EUR is accepted.",
            "allOf": [
              {
                "$ref": "#/components/schemas/Money"
              }
            ]
          },
          "additionalInfo": {
            "type": "string",
            "nullable": true,
            "maxLength": 2000,
            "minLength": 10
          }
        },
        "type": "object"
      },
      "ManagedServiceRequestSent": {
        "required": [
          "status"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "sent"
            ]
          }
        },
        "type": "object"
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "The API key is missing, malformed, unknown, revoked or expired, or its account cannot sign in (code `unauthorized`).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Forbidden": {
        "description": "The key lacks the capability the operation needs (code `insufficient_capability`), or the account may not perform it (code `forbidden`).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "CatalogueForbidden": {
        "description": "The catalogue is open to accounts with recent completed orders, as buyer or as seller, and this account has none (code `catalogue_requires_recent_order`). GET /me reports `catalogue.eligible`.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "TooManyRequests": {
        "description": "Over the rate limit (code `rate_limit_exceeded`), or too many failed authentications from this address (code `too_many_failed_authentications`). On the catalogue operations, also when the response would take the account beyond the distinct medias it may see per UTC day (code `catalogue_daily_cap_reached`): `details.remaining` says how many new medias still fit today, `Retry-After` is the time to the next UTC midnight, and medias already seen today stay readable. On the managed service requests, also when you sent as many requests of that kind as you may per UTC day (code `managed_service_request_limit_reached`): `Retry-After` is the time to the next UTC midnight.",
        "headers": {
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "ServiceUnavailable": {
        "description": "The rate limiter cannot be reached, so the call is refused (code `rate_limit_unavailable`), or a stored file cannot be read right now (code `storage_unavailable`). Retry later.",
        "headers": {
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "InternalError": {
        "description": "An unexpected error (code `internal_error`).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "BadRequest": {
        "description": "The write has no `Idempotency-Key` header (code `idempotency_key_required`), the header is not 1 to 255 printable ASCII characters without spaces (code `invalid_idempotency_key`), or the body is not a JSON object (code `invalid_json`).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "NotFound": {
        "description": "The resource does not exist, or it is not yours (code `not_found`).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "IdempotencyConflict": {
        "description": "The `Idempotency-Key` was used for a different request (code `idempotency_key_reused`), its first request is still running (code `idempotency_request_in_progress`), or its first request failed and may have taken effect (code `idempotency_outcome_unknown`).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "ValidationFailed": {
        "description": "The request is not valid (code `validation_failed`). `details.fields` holds the messages for each invalid field, by field name.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "code": "validation_failed",
              "message": "The request is not valid. See details for each field.",
              "requestId": "3f2a9c1e7b4d4e0a",
              "details": {
                "fields": {
                  "promotedProducts": [
                    "This collection should contain 5 elements or more."
                  ]
                }
              }
            }
          }
        }
      }
    },
    "parameters": {
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "description": "A new key for each write, reused only to retry that same write. 1 to 255 printable ASCII characters without spaces (`!` to `~`); any other value answers 400 `invalid_idempotency_key`.",
        "required": true,
        "schema": {
          "type": "string",
          "maxLength": 255
        }
      },
      "CatalogueSource": {
        "name": "source",
        "in": "query",
        "description": "Which of the project's medias to search: `all` (the default), `recommended` (those Growwer recommends for the project), or those you marked `favourite`, `discarded` or `requested`, or `bought` for the project. Do not combine it with the parameter of the same state.",
        "required": false,
        "schema": {
          "type": "string",
          "enum": [
            "all",
            "recommended",
            "favourite",
            "discarded",
            "requested",
            "bought"
          ]
        }
      },
      "CatalogueSort": {
        "name": "sort",
        "in": "query",
        "description": "The order. Without it, the web's default order: medias on the project's topic and language first, then best sellers and medias with more published orders. Ties are always broken by media id, so pages never overlap. `-growwerRank`: best match first; `postPrice`, `linkAdditionPrice`: cheapest first; `matchedAt`, `-matchedAt`: when Growwer matched the media with the project; `-traffic`, `-domainRating`, `-referringDomains`: highest first; `linkedToReferringRatio`: lowest first.",
        "required": false,
        "schema": {
          "type": "string",
          "enum": [
            "-growwerRank",
            "postPrice",
            "linkAdditionPrice",
            "matchedAt",
            "-matchedAt",
            "-traffic",
            "-domainRating",
            "linkedToReferringRatio",
            "-referringDomains"
          ]
        }
      },
      "CatalogueDomain": {
        "name": "domain",
        "in": "query",
        "description": "Medias whose domain contains this text, 1 to 255 characters.",
        "required": false,
        "schema": {
          "type": "string"
        }
      },
      "CatalogueWebsiteType": {
        "name": "websiteType",
        "in": "query",
        "description": "A comma-separated list of website types: `blog`, `press`.",
        "required": false,
        "schema": {
          "type": "string"
        }
      },
      "CatalogueLanguage": {
        "name": "language",
        "in": "query",
        "description": "A comma-separated list of language codes, as in GET /vocabulary.",
        "required": false,
        "schema": {
          "type": "string"
        }
      },
      "CatalogueCountry": {
        "name": "country",
        "in": "query",
        "description": "A comma-separated list of country codes, as in GET /vocabulary.",
        "required": false,
        "schema": {
          "type": "string"
        }
      },
      "CatalogueTopics": {
        "name": "topics",
        "in": "query",
        "description": "A comma-separated list of topic ids, as in GET /vocabulary: medias on any of them.",
        "required": false,
        "schema": {
          "type": "string"
        }
      },
      "CatalogueNotBannedTopics": {
        "name": "notBannedTopics",
        "in": "query",
        "description": "Leave out medias that refuse the topic of the project. Only `true` applies it; omit it otherwise.",
        "required": false,
        "schema": {
          "type": "boolean"
        }
      },
      "CatalogueMinTraffic": {
        "name": "minTraffic",
        "in": "query",
        "description": "Minimum monthly organic traffic.",
        "required": false,
        "schema": {
          "type": "integer"
        }
      },
      "CatalogueMaxTraffic": {
        "name": "maxTraffic",
        "in": "query",
        "description": "Maximum monthly organic traffic.",
        "required": false,
        "schema": {
          "type": "integer"
        }
      },
      "CatalogueTrafficTrendUpward": {
        "name": "trafficTrendUpward",
        "in": "query",
        "description": "Medias whose traffic is growing. Only `true` applies it; omit it otherwise.",
        "required": false,
        "schema": {
          "type": "boolean"
        }
      },
      "CatalogueMinDomainRating": {
        "name": "minDomainRating",
        "in": "query",
        "description": "Minimum domain rating, 0 to 100.",
        "required": false,
        "schema": {
          "type": "integer"
        }
      },
      "CatalogueMaxDomainRating": {
        "name": "maxDomainRating",
        "in": "query",
        "description": "Maximum domain rating, 0 to 100.",
        "required": false,
        "schema": {
          "type": "integer"
        }
      },
      "CatalogueMinLinkedToReferringRatio": {
        "name": "minLinkedToReferringRatio",
        "in": "query",
        "description": "Minimum ratio of linked domains to referring domains, such as 0.5.",
        "required": false,
        "schema": {
          "type": "number"
        }
      },
      "CatalogueMaxLinkedToReferringRatio": {
        "name": "maxLinkedToReferringRatio",
        "in": "query",
        "description": "Maximum ratio of linked domains to referring domains, such as 1.5.",
        "required": false,
        "schema": {
          "type": "number"
        }
      },
      "CatalogueMinPostPrice": {
        "name": "minPostPrice",
        "in": "query",
        "description": "Minimum post price, in cents.",
        "required": false,
        "schema": {
          "type": "integer"
        }
      },
      "CatalogueMaxPostPrice": {
        "name": "maxPostPrice",
        "in": "query",
        "description": "Maximum post price, in cents.",
        "required": false,
        "schema": {
          "type": "integer"
        }
      },
      "CataloguePostLinkType": {
        "name": "postLinkType",
        "in": "query",
        "description": "A comma-separated list of link types the post offer gives: `dofollow`, `nofollow`, `citation`.",
        "required": false,
        "schema": {
          "type": "string"
        }
      },
      "CataloguePromotedSocialNetwork": {
        "name": "promotedSocialNetwork",
        "in": "query",
        "description": "A comma-separated list of social networks the media promotes posts on: `twitter`, `instagram`, `facebook`, `pinterest`, `tumblr`, `newsletter`.",
        "required": false,
        "schema": {
          "type": "string"
        }
      },
      "CatalogueWithoutAdvertisingLabel": {
        "name": "withoutAdvertisingLabel",
        "in": "query",
        "description": "Medias that never label posts as advertising. Only `true` applies it; omit it otherwise.",
        "required": false,
        "schema": {
          "type": "boolean"
        }
      },
      "CatalogueHomepageListing": {
        "name": "homepageListing",
        "in": "query",
        "description": "Medias that offer listing the post on their homepage. Only `true` applies it; omit it otherwise.",
        "required": false,
        "schema": {
          "type": "boolean"
        }
      },
      "CatalogueHasLinkAddition": {
        "name": "hasLinkAddition",
        "in": "query",
        "description": "Medias that offer adding a link to an existing article. Only `true` applies it; omit it otherwise.",
        "required": false,
        "schema": {
          "type": "boolean"
        }
      },
      "CatalogueMinLinkAdditionPrice": {
        "name": "minLinkAdditionPrice",
        "in": "query",
        "description": "Minimum link addition price, in cents.",
        "required": false,
        "schema": {
          "type": "integer"
        }
      },
      "CatalogueMaxLinkAdditionPrice": {
        "name": "maxLinkAdditionPrice",
        "in": "query",
        "description": "Maximum link addition price, in cents.",
        "required": false,
        "schema": {
          "type": "integer"
        }
      },
      "CatalogueLinkAdditionLinkType": {
        "name": "linkAdditionLinkType",
        "in": "query",
        "description": "A comma-separated list of link types the link addition offer gives: `dofollow`, `nofollow`, `citation`.",
        "required": false,
        "schema": {
          "type": "string"
        }
      },
      "CatalogueRecommended": {
        "name": "recommended",
        "in": "query",
        "description": "`true`: only the medias Growwer recommends for the project; `false`: only the others.",
        "required": false,
        "schema": {
          "type": "boolean"
        }
      },
      "CatalogueFavourite": {
        "name": "favourite",
        "in": "query",
        "description": "`true`: only your favourites for the project; `false`: leave them out.",
        "required": false,
        "schema": {
          "type": "boolean"
        }
      },
      "CatalogueRequested": {
        "name": "requested",
        "in": "query",
        "description": "`true`: only the medias you requested for the project; `false`: leave them out.",
        "required": false,
        "schema": {
          "type": "boolean"
        }
      },
      "CatalogueFlashOffer": {
        "name": "flashOffer",
        "in": "query",
        "description": "`true`: only medias with a flash offer running; `false`: leave them out.",
        "required": false,
        "schema": {
          "type": "boolean"
        }
      },
      "CatalogueBought": {
        "name": "bought",
        "in": "query",
        "description": "`true`: only medias you bought for the project; `false`: leave them out.",
        "required": false,
        "schema": {
          "type": "boolean"
        }
      },
      "CatalogueDiscarded": {
        "name": "discarded",
        "in": "query",
        "description": "`true`: only the medias you discarded for the project; `false`: leave them out.",
        "required": false,
        "schema": {
          "type": "boolean"
        }
      },
      "CatalogueNew": {
        "name": "new",
        "in": "query",
        "description": "Medias Growwer matched with the project recently. Only `true` applies it; omit it otherwise.",
        "required": false,
        "schema": {
          "type": "boolean"
        }
      },
      "CatalogueRanksGoalKeyword": {
        "name": "ranksGoalKeyword",
        "in": "query",
        "description": "A comma-separated list of keyword origins: medias that rank for a keyword of the project from any of them. `user`: your keywords; `publicGenerated`: keywords Growwer found for the project.",
        "required": false,
        "schema": {
          "type": "string"
        }
      },
      "CatalogueRanksAiKeyword": {
        "name": "ranksAiKeyword",
        "in": "query",
        "description": "A comma-separated list of AI answer engines: medias cited for a keyword of the project by any of them. `googleAiOverview`, `chatgpt`, `googleAiMode`.",
        "required": false,
        "schema": {
          "type": "string"
        }
      }
    },
    "headers": {
      "RetryAfter": {
        "description": "Seconds to wait before retrying.",
        "schema": {
          "type": "integer"
        }
      },
      "RateLimitLimit": {
        "description": "Requests allowed in the current window.",
        "schema": {
          "type": "integer"
        }
      },
      "RateLimitRemaining": {
        "description": "Requests left in the current window.",
        "schema": {
          "type": "integer"
        }
      },
      "RateLimitReset": {
        "description": "Seconds until the current window resets.",
        "schema": {
          "type": "integer"
        }
      }
    },
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "description": "An API key from your profile page.",
        "scheme": "bearer"
      }
    }
  },
  "security": [
    {
      "apiKey": []
    }
  ],
  "tags": [
    {
      "name": "Account",
      "description": "Account"
    },
    {
      "name": "Saved filters",
      "description": "Saved filters"
    },
    {
      "name": "Catalogue",
      "description": "Catalogue"
    },
    {
      "name": "Files",
      "description": "Files"
    },
    {
      "name": "Buyer money",
      "description": "Buyer money"
    },
    {
      "name": "Managed services",
      "description": "Managed services"
    },
    {
      "name": "Orders",
      "description": "Orders"
    },
    {
      "name": "Projects",
      "description": "Projects"
    },
    {
      "name": "Seller medias",
      "description": "Seller medias"
    },
    {
      "name": "Seller money",
      "description": "Seller money"
    },
    {
      "name": "Seller orders",
      "description": "Seller orders"
    }
  ]
}
