{
  "openapi": "3.1.0",
  "info": {
    "title": "Taskora public catalog API",
    "version": "1.0.0",
    "summary": "Read-only JSON API of Taskora, a freelance marketplace demo by AdScaled.",
    "description": "Search freelancers, jobs, categories and companies of the Taskora demo marketplace. All operations are anonymous GET requests that return JSON. All people, companies, jobs, reviews and amounts are fictional demo data generated for Taskora, a demo product by AdScaled. Never present them as real offers, real people or real prices. Signing in, posting jobs, proposals, contracts, payments and messages are not part of this public API. Errors use `{ \"error\": { \"code\", \"message\" } }`. Every /api response carries the IETF `RateLimit-Policy` and `RateLimit` headers; all /api paths share 600 requests per minute per client IP, and a 429 adds `Retry-After` in seconds. The API is versioned in the URL path: the current major version is v1 (`/api/v1/...`, OpenAPI `info.version` 1.x). Additive, backward-compatible changes (new operations, optional parameters or response fields) keep v1 and raise the minor version in `info.version`. Breaking changes (removed or renamed fields, operations or parameters, changed types or meanings) are only released under a new major version path such as `/api/v2/`, and the previous version keeps working alongside it. Deprecated operations are marked `deprecated: true` in the OpenAPI description and announced in this documentation and in /llms.txt, and their responses then carry the `Deprecation` header (RFC 9745) and a `Sunset` header with the shutdown date (RFC 8594), plus a `Link` with `rel=\"deprecation\"` pointing to these docs. A deprecated operation stays available for at least 90 days after the deprecation is announced. The unversioned `/api/...` paths are the same v1 handlers kept for compatibility; new integrations should use `/api/v1/`. No operation is deprecated today.",
    "contact": {
      "name": "AdScaled",
      "url": "https://www.adscaled.media/en/contact",
      "email": "contact@adscaled.media"
    }
  },
  "servers": [
    {
      "url": "https://freelance.adscaled.media"
    }
  ],
  "externalDocs": {
    "description": "Human-readable API documentation",
    "url": "https://freelance.adscaled.media/api/docs"
  },
  "tags": [
    {
      "name": "catalog",
      "description": "Public marketplace catalog (fictional demo data)."
    }
  ],
  "paths": {
    "/api/v1/health": {
      "get": {
        "tags": [
          "catalog"
        ],
        "operationId": "getHealth",
        "summary": "Service health",
        "description": "Returns `{ \"ok\": true }` while the service is up. Not rate limited by an endpoint policy.",
        "responses": {
          "200": {
            "description": "The service is up.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Health"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "description": "Remaining quota and seconds until the window resets, e.g. `\"global\";r=599;t=60`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "Quota and window in seconds, e.g. `\"global\";q=600;w=60`.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api/v1/categories": {
      "get": {
        "tags": [
          "catalog"
        ],
        "operationId": "listCategories",
        "summary": "List categories",
        "description": "All 35 categories in 5 groups with the number of public freelancer profiles and open jobs in each.",
        "responses": {
          "200": {
            "description": "Every category.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Category"
                  }
                }
              }
            },
            "headers": {
              "RateLimit": {
                "description": "Remaining quota and seconds until the window resets, e.g. `\"global\";r=599;t=60`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "Quota and window in seconds, e.g. `\"global\";q=600;w=60`.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api/v1/freelancers": {
      "get": {
        "tags": [
          "catalog"
        ],
        "operationId": "searchFreelancers",
        "summary": "Search freelancers",
        "description": "Public freelancer profiles with filters, sorting, paging and facets (countries, languages, skills).",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": false,
            "description": "Free-text search (up to 6 words; names, titles, skills and category names are matched).",
            "schema": {
              "type": "string",
              "maxLength": 120
            }
          },
          {
            "name": "group",
            "in": "query",
            "required": false,
            "description": "Category group slug.",
            "schema": {
              "type": "string",
              "enum": [
                "development",
                "design",
                "marketing",
                "video-audio",
                "business"
              ]
            }
          },
          {
            "name": "category",
            "in": "query",
            "required": false,
            "description": "Category slug (see listCategories).",
            "schema": {
              "type": "string",
              "enum": [
                "frontend-development",
                "backend-development",
                "full-stack-development",
                "mobile-development",
                "wordpress",
                "ecommerce",
                "devops",
                "ai-machine-learning",
                "cybersecurity",
                "automation",
                "ui-ux-design",
                "web-design",
                "graphic-design",
                "logo-design",
                "branding",
                "3d-design",
                "illustration",
                "seo",
                "google-ads",
                "meta-ads",
                "social-media",
                "email-marketing",
                "copywriting",
                "content-strategy",
                "video-editing",
                "animation",
                "motion-design",
                "voice-over",
                "music-production",
                "accounting",
                "consulting",
                "virtual-assistant",
                "data-entry",
                "legal",
                "project-management"
              ]
            }
          },
          {
            "name": "skills",
            "in": "query",
            "required": false,
            "description": "Comma-separated skill names, all must match (up to 8).",
            "schema": {
              "type": "string",
              "maxLength": 400
            }
          },
          {
            "name": "rateMin",
            "in": "query",
            "required": false,
            "description": "Minimum hourly rate in USD.",
            "schema": {
              "type": "number",
              "minimum": 0
            }
          },
          {
            "name": "rateMax",
            "in": "query",
            "required": false,
            "description": "Maximum hourly rate in USD.",
            "schema": {
              "type": "number",
              "minimum": 0
            }
          },
          {
            "name": "rating",
            "in": "query",
            "required": false,
            "description": "Minimum average rating.",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 5
            }
          },
          {
            "name": "country",
            "in": "query",
            "required": false,
            "description": "Country name, case-insensitive.",
            "schema": {
              "type": "string",
              "maxLength": 60
            }
          },
          {
            "name": "language",
            "in": "query",
            "required": false,
            "description": "Spoken language name, case-insensitive.",
            "schema": {
              "type": "string",
              "maxLength": 40
            }
          },
          {
            "name": "level",
            "in": "query",
            "required": false,
            "description": "Experience level.",
            "schema": {
              "type": "string",
              "enum": [
                "entry",
                "intermediate",
                "expert"
              ]
            }
          },
          {
            "name": "availability",
            "in": "query",
            "required": false,
            "description": "Availability.",
            "schema": {
              "type": "string",
              "enum": [
                "available",
                "limited",
                "unavailable"
              ]
            }
          },
          {
            "name": "verified",
            "in": "query",
            "required": false,
            "description": "`1` = identity-verified only.",
            "schema": {
              "type": "string",
              "enum": [
                "1"
              ]
            }
          },
          {
            "name": "topRated",
            "in": "query",
            "required": false,
            "description": "`1` = Top Rated only.",
            "schema": {
              "type": "string",
              "enum": [
                "1"
              ]
            }
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort order.",
            "schema": {
              "type": "string",
              "enum": [
                "recommended",
                "rating",
                "price_low",
                "price_high",
                "reviews",
                "recent"
              ],
              "default": "recommended"
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Page number, starting at 1.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 10000,
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "required": false,
            "description": "Items per page.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "default": 20
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of freelancers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FreelancerSearchResult"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "description": "Remaining quota and seconds until the window resets, e.g. `\"global\";r=599;t=60`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "Quota and window in seconds, e.g. `\"global\";q=600;w=60`.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api/v1/freelancers/{handle}": {
      "get": {
        "tags": [
          "catalog"
        ],
        "operationId": "getFreelancer",
        "summary": "Get a freelancer profile",
        "description": "Full public profile. Private and suspended profiles answer 404. Each call counts as a profile view in the demo statistics.",
        "parameters": [
          {
            "name": "handle",
            "in": "path",
            "required": true,
            "description": "Profile handle, e.g. `alex-morgan`.",
            "schema": {
              "type": "string",
              "maxLength": 160
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The profile.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FreelancerProfile"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "description": "Remaining quota and seconds until the window resets, e.g. `\"global\";r=599;t=60`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "Quota and window in seconds, e.g. `\"global\";q=600;w=60`.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api/v1/freelancers/{handle}/work/{slug}": {
      "get": {
        "tags": [
          "catalog"
        ],
        "operationId": "getFreelancerCaseStudy",
        "summary": "Get a portfolio case study",
        "description": "One case study of a public profile with the freelancer card and up to 4 more case studies.",
        "parameters": [
          {
            "name": "handle",
            "in": "path",
            "required": true,
            "description": "Profile handle.",
            "schema": {
              "type": "string",
              "maxLength": 160
            }
          },
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "description": "Case study slug.",
            "schema": {
              "type": "string",
              "maxLength": 160
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The case study.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CaseStudy"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "description": "Remaining quota and seconds until the window resets, e.g. `\"global\";r=599;t=60`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "Quota and window in seconds, e.g. `\"global\";q=600;w=60`.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api/v1/jobs": {
      "get": {
        "tags": [
          "catalog"
        ],
        "operationId": "searchJobs",
        "summary": "Search jobs",
        "description": "Open jobs (or all jobs with `status=all`) with filters, sorting and paging.",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": false,
            "description": "Free-text search (up to 6 words; names, titles, skills and category names are matched).",
            "schema": {
              "type": "string",
              "maxLength": 120
            }
          },
          {
            "name": "group",
            "in": "query",
            "required": false,
            "description": "Category group slug.",
            "schema": {
              "type": "string",
              "enum": [
                "development",
                "design",
                "marketing",
                "video-audio",
                "business"
              ]
            }
          },
          {
            "name": "category",
            "in": "query",
            "required": false,
            "description": "Category slug (see listCategories).",
            "schema": {
              "type": "string",
              "enum": [
                "frontend-development",
                "backend-development",
                "full-stack-development",
                "mobile-development",
                "wordpress",
                "ecommerce",
                "devops",
                "ai-machine-learning",
                "cybersecurity",
                "automation",
                "ui-ux-design",
                "web-design",
                "graphic-design",
                "logo-design",
                "branding",
                "3d-design",
                "illustration",
                "seo",
                "google-ads",
                "meta-ads",
                "social-media",
                "email-marketing",
                "copywriting",
                "content-strategy",
                "video-editing",
                "animation",
                "motion-design",
                "voice-over",
                "music-production",
                "accounting",
                "consulting",
                "virtual-assistant",
                "data-entry",
                "legal",
                "project-management"
              ]
            }
          },
          {
            "name": "type",
            "in": "query",
            "required": false,
            "description": "Budget type.",
            "schema": {
              "type": "string",
              "enum": [
                "fixed",
                "hourly"
              ]
            }
          },
          {
            "name": "budgetMin",
            "in": "query",
            "required": false,
            "description": "Jobs whose maximum budget is at least this many USD.",
            "schema": {
              "type": "number",
              "minimum": 0
            }
          },
          {
            "name": "budgetMax",
            "in": "query",
            "required": false,
            "description": "Jobs whose minimum budget is at most this many USD.",
            "schema": {
              "type": "number",
              "minimum": 0
            }
          },
          {
            "name": "level",
            "in": "query",
            "required": false,
            "description": "Experience level.",
            "schema": {
              "type": "string",
              "enum": [
                "entry",
                "intermediate",
                "expert"
              ]
            }
          },
          {
            "name": "duration",
            "in": "query",
            "required": false,
            "description": "Project length in months.",
            "schema": {
              "type": "string",
              "enum": [
                "lt1",
                "1to3",
                "3to6",
                "gt6"
              ]
            }
          },
          {
            "name": "proposals",
            "in": "query",
            "required": false,
            "description": "Number of proposals so far.",
            "schema": {
              "type": "string",
              "enum": [
                "lt5",
                "5to10",
                "10to20",
                "gt20"
              ]
            }
          },
          {
            "name": "verified",
            "in": "query",
            "required": false,
            "description": "`1` = clients with a verified payment method only.",
            "schema": {
              "type": "string",
              "enum": [
                "1"
              ]
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "`all` includes jobs that are no longer open.",
            "schema": {
              "type": "string",
              "enum": [
                "all"
              ]
            }
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort order.",
            "schema": {
              "type": "string",
              "enum": [
                "newest",
                "budget_high",
                "budget_low",
                "proposals_low"
              ],
              "default": "newest"
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Page number, starting at 1.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 10000,
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "required": false,
            "description": "Items per page.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "default": 20
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of jobs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobSearchResult"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "description": "Remaining quota and seconds until the window resets, e.g. `\"global\";r=599;t=60`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "Quota and window in seconds, e.g. `\"global\";q=600;w=60`.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api/v1/jobs/{slug}": {
      "get": {
        "tags": [
          "catalog"
        ],
        "operationId": "getJob",
        "summary": "Get a job",
        "description": "Job details with the client card and similar jobs. Each call counts as a job view in the demo statistics.",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "description": "Job slug.",
            "schema": {
              "type": "string",
              "maxLength": 160
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The job.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobDetail"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "description": "Remaining quota and seconds until the window resets, e.g. `\"global\";r=599;t=60`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "Quota and window in seconds, e.g. `\"global\";q=600;w=60`.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api/v1/companies/{slug}": {
      "get": {
        "tags": [
          "catalog"
        ],
        "operationId": "getCompany",
        "summary": "Get a company page",
        "description": "Company profile with open jobs, reviews from freelancers and the hiring team.",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "description": "Company slug, e.g. `novatech`.",
            "schema": {
              "type": "string",
              "maxLength": 160
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The company.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Company"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "description": "Remaining quota and seconds until the window resets, e.g. `\"global\";r=599;t=60`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "Quota and window in seconds, e.g. `\"global\";q=600;w=60`.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api/v1/search/suggest": {
      "get": {
        "tags": [
          "catalog"
        ],
        "operationId": "suggestSearch",
        "summary": "Search suggestions",
        "description": "Up to 5 matching freelancers, jobs, skills, companies and categories. Queries shorter than 2 characters return empty lists.",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "description": "Search text (2 to 60 characters).",
            "schema": {
              "type": "string",
              "minLength": 2,
              "maxLength": 60
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Suggestions.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Suggestions"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "description": "Remaining quota and seconds until the window resets, e.g. `\"global\";r=599;t=60`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "Quota and window in seconds, e.g. `\"global\";q=600;w=60`.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Error": {
        "description": "The one error model of the API: every non-2xx JSON response has this shape.",
        "type": "object",
        "required": [
          "error"
        ],
        "additionalProperties": false,
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string",
                "description": "Stable machine-readable error code.",
                "examples": [
                  "not_found",
                  "method_not_allowed",
                  "rate_limited",
                  "internal"
                ]
              },
              "message": {
                "type": "string",
                "description": "Human-readable explanation in English."
              },
              "fields": {
                "type": "object",
                "additionalProperties": {
                  "type": "string"
                },
                "description": "Per-field validation messages (only on validation errors)."
              }
            }
          }
        }
      },
      "Health": {
        "type": "object",
        "required": [
          "ok"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "const": true
          }
        }
      },
      "Category": {
        "type": "object",
        "required": [
          "slug",
          "name",
          "group",
          "blurb",
          "freelancers",
          "openJobs"
        ],
        "properties": {
          "slug": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "group": {
            "type": "string",
            "enum": [
              "development",
              "design",
              "marketing",
              "video-audio",
              "business"
            ]
          },
          "blurb": {
            "type": "string"
          },
          "freelancers": {
            "type": "integer",
            "description": "Public freelancer profiles in this category."
          },
          "openJobs": {
            "type": "integer",
            "description": "Open jobs in this category."
          }
        }
      },
      "FreelancerCard": {
        "type": "object",
        "required": [
          "id",
          "handle",
          "name",
          "title",
          "category",
          "hourlyRate",
          "rating",
          "reviewsCount"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "handle": {
            "type": "string",
            "description": "Profile URL: https://freelance.adscaled.media/freelancers/{handle}"
          },
          "name": {
            "type": "string"
          },
          "avatar": {
            "type": "string",
            "description": "Image path relative to the site origin."
          },
          "country": {
            "type": "string"
          },
          "city": {
            "type": "string"
          },
          "online": {
            "type": "boolean"
          },
          "verified": {
            "type": "boolean"
          },
          "topRated": {
            "type": "boolean"
          },
          "title": {
            "type": "string"
          },
          "summary": {
            "type": "string"
          },
          "category": {
            "type": "string"
          },
          "rating": {
            "type": "number",
            "minimum": 0,
            "maximum": 5
          },
          "reviewsCount": {
            "type": "integer"
          },
          "jobsCompleted": {
            "type": "integer"
          },
          "hourlyRate": {
            "type": "number",
            "description": "US dollars per hour (fictional)."
          },
          "skills": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "availability": {
            "type": "string",
            "enum": [
              "available",
              "limited",
              "unavailable"
            ]
          },
          "level": {
            "type": "string",
            "enum": [
              "entry",
              "intermediate",
              "expert"
            ]
          },
          "saved": {
            "type": "boolean",
            "description": "Always false for anonymous requests."
          },
          "lastActiveAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Facet": {
        "type": "object",
        "required": [
          "value",
          "count"
        ],
        "properties": {
          "value": {
            "type": "string"
          },
          "count": {
            "type": "integer"
          }
        }
      },
      "FreelancerSearchResult": {
        "type": "object",
        "required": [
          "items",
          "total",
          "page",
          "pageSize",
          "facets"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FreelancerCard"
            }
          },
          "total": {
            "type": "integer"
          },
          "page": {
            "type": "integer"
          },
          "pageSize": {
            "type": "integer"
          },
          "facets": {
            "type": "object",
            "properties": {
              "countries": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Facet"
                }
              },
              "languages": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Facet"
                }
              },
              "skills": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Facet"
                }
              }
            }
          }
        }
      },
      "PortfolioSummary": {
        "type": "object",
        "required": [
          "slug",
          "title",
          "summary"
        ],
        "properties": {
          "slug": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "summary": {
            "type": "string"
          },
          "cover": {
            "type": "string"
          },
          "technologies": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "category": {
            "type": "string"
          },
          "year": {
            "type": "integer"
          }
        }
      },
      "FreelancerProfile": {
        "description": "A freelancer card plus bio, languages, experience, portfolio, work history, reviews and similar profiles.",
        "allOf": [
          {
            "$ref": "#/components/schemas/FreelancerCard"
          },
          {
            "type": "object",
            "properties": {
              "bio": {
                "type": "string"
              },
              "timezone": {
                "type": "string"
              },
              "languages": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "level": {
                      "type": "string"
                    }
                  }
                }
              },
              "successRate": {
                "type": "number"
              },
              "memberSince": {
                "type": "string",
                "format": "date-time"
              },
              "portfolio": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/PortfolioSummary"
                }
              },
              "workHistory": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              },
              "reviews": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              },
              "similar": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/FreelancerCard"
                }
              }
            }
          }
        ]
      },
      "CaseStudy": {
        "type": "object",
        "required": [
          "item",
          "freelancer",
          "more"
        ],
        "properties": {
          "item": {
            "allOf": [
              {
                "$ref": "#/components/schemas/PortfolioSummary"
              },
              {
                "type": "object",
                "properties": {
                  "client": {
                    "type": "string"
                  },
                  "challenge": {
                    "type": "string"
                  },
                  "solution": {
                    "type": "string"
                  },
                  "process": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "title": {
                          "type": "string"
                        },
                        "text": {
                          "type": "string"
                        }
                      }
                    }
                  },
                  "results": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "label": {
                          "type": "string"
                        },
                        "value": {
                          "type": "string"
                        }
                      }
                    }
                  },
                  "duration": {
                    "type": "string"
                  },
                  "images": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              }
            ]
          },
          "freelancer": {
            "$ref": "#/components/schemas/FreelancerCard"
          },
          "more": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PortfolioSummary"
            }
          }
        }
      },
      "JobCard": {
        "type": "object",
        "required": [
          "id",
          "slug",
          "title",
          "category",
          "budgetType",
          "budgetMin",
          "budgetMax",
          "status",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "slug": {
            "type": "string",
            "description": "Job URL: https://freelance.adscaled.media/jobs/{slug}"
          },
          "title": {
            "type": "string"
          },
          "excerpt": {
            "type": "string"
          },
          "category": {
            "type": "string"
          },
          "budgetType": {
            "type": "string",
            "enum": [
              "fixed",
              "hourly"
            ]
          },
          "budgetMin": {
            "type": "number",
            "description": "US dollars (per hour for hourly jobs)."
          },
          "budgetMax": {
            "type": "number"
          },
          "level": {
            "type": "string",
            "enum": [
              "entry",
              "intermediate",
              "expert"
            ]
          },
          "duration": {
            "type": "string",
            "enum": [
              "lt1",
              "1to3",
              "3to6",
              "gt6"
            ],
            "description": "Months: under 1, 1 to 3, 3 to 6, over 6."
          },
          "skills": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "proposalsCount": {
            "type": "integer"
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "in_progress",
              "completed",
              "closed"
            ]
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "client": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "country": {
                "type": "string"
              },
              "paymentVerified": {
                "type": "boolean"
              },
              "rating": {
                "type": "number"
              },
              "totalSpent": {
                "type": "number"
              },
              "companySlug": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "saved": {
            "type": "boolean"
          }
        }
      },
      "JobSearchResult": {
        "type": "object",
        "required": [
          "items",
          "total",
          "page",
          "pageSize"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/JobCard"
            }
          },
          "total": {
            "type": "integer"
          },
          "page": {
            "type": "integer"
          },
          "pageSize": {
            "type": "integer"
          }
        }
      },
      "JobDetail": {
        "allOf": [
          {
            "$ref": "#/components/schemas/JobCard"
          },
          {
            "type": "object",
            "properties": {
              "description": {
                "type": "string"
              },
              "hoursPerWeek": {
                "type": [
                  "string",
                  "null"
                ],
                "enum": [
                  "lt10",
                  "10to30",
                  "gt30",
                  null
                ]
              },
              "views": {
                "type": "integer"
              },
              "invitesSent": {
                "type": "integer"
              },
              "interviewing": {
                "type": "integer"
              },
              "clientCard": {
                "type": "object"
              },
              "similar": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/JobCard"
                }
              }
            }
          }
        ]
      },
      "Company": {
        "type": "object",
        "required": [
          "slug",
          "name",
          "tagline",
          "description"
        ],
        "properties": {
          "slug": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "tagline": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "industry": {
            "type": "string"
          },
          "size": {
            "type": "string"
          },
          "location": {
            "type": "string"
          },
          "founded": {
            "type": "integer"
          },
          "totalHires": {
            "type": "integer"
          },
          "rating": {
            "type": "number"
          },
          "reviewsCount": {
            "type": "integer"
          },
          "openJobs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/JobCard"
            }
          }
        }
      },
      "Suggestions": {
        "type": "object",
        "required": [
          "freelancers",
          "jobs",
          "skills",
          "companies",
          "categories"
        ],
        "properties": {
          "freelancers": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "handle": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                }
              }
            }
          },
          "jobs": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "slug": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                },
                "category": {
                  "type": "string"
                }
              }
            }
          },
          "skills": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "companies": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "slug": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                }
              }
            }
          },
          "categories": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "slug": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "headers": {
      "RateLimit": {
        "description": "Remaining quota and seconds until the window resets, e.g. `\"global\";r=599;t=60`.",
        "schema": {
          "type": "string"
        }
      },
      "RateLimit-Policy": {
        "description": "Quota and window in seconds, e.g. `\"global\";q=600;w=60`.",
        "schema": {
          "type": "string"
        }
      }
    },
    "responses": {
      "NotFound": {
        "description": "The record does not exist or is not public.",
        "headers": {
          "RateLimit": {
            "description": "Remaining quota and seconds until the window resets, e.g. `\"global\";r=599;t=60`.",
            "schema": {
              "type": "string"
            }
          },
          "RateLimit-Policy": {
            "description": "Quota and window in seconds, e.g. `\"global\";q=600;w=60`.",
            "schema": {
              "type": "string"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "MethodNotAllowed": {
        "description": "Only GET and HEAD are allowed on the public API: the `Allow` header lists the allowed methods.",
        "headers": {
          "RateLimit": {
            "description": "Remaining quota and seconds until the window resets, e.g. `\"global\";r=599;t=60`.",
            "schema": {
              "type": "string"
            }
          },
          "RateLimit-Policy": {
            "description": "Quota and window in seconds, e.g. `\"global\";q=600;w=60`.",
            "schema": {
              "type": "string"
            }
          },
          "Allow": {
            "description": "Allowed methods, e.g. `GET, HEAD`.",
            "schema": {
              "type": "string"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "InternalError": {
        "description": "Unexpected server error; safe to retry later.",
        "headers": {
          "RateLimit": {
            "description": "Remaining quota and seconds until the window resets, e.g. `\"global\";r=599;t=60`.",
            "schema": {
              "type": "string"
            }
          },
          "RateLimit-Policy": {
            "description": "Quota and window in seconds, e.g. `\"global\";q=600;w=60`.",
            "schema": {
              "type": "string"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "TooManyRequests": {
        "description": "Rate limit exceeded: wait `Retry-After` seconds before the next request, do not retry in a loop.",
        "headers": {
          "RateLimit": {
            "description": "Remaining quota and seconds until the window resets, e.g. `\"global\";r=599;t=60`.",
            "schema": {
              "type": "string"
            }
          },
          "RateLimit-Policy": {
            "description": "Quota and window in seconds, e.g. `\"global\";q=600;w=60`.",
            "schema": {
              "type": "string"
            }
          },
          "Retry-After": {
            "description": "Seconds to wait.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    }
  }
}