{
 "openapi": "3.1.0",
 "info": {
  "title": "Frevia Freelance API",
  "version": "1.0.0",
  "description": "Search freelance services, place orders, message sellers and track delivery on Frevia Freelance. Search is public; acting for a user needs their API key (Authorization: Bearer fvk_…). Orders return a payUrl the user opens to pay — agents never handle card details."
 },
 "servers": [
  {
   "url": "https://freviafreelance.com"
  }
 ],
 "components": {
  "securitySchemes": {
   "apiKey": {
    "type": "http",
    "scheme": "bearer",
    "description": "Personal key from /settings/api-keys"
   }
  },
  "schemas": {}
 },
 "paths": {
  "/api/v1/categories": {
   "get": {
    "operationId": "list_categories",
    "summary": "List categories",
    "description": "All Frevia Freelance service categories (slug + name). Use a slug as the `category` filter in search_services or search_jobs.",
    "responses": {
     "200": {
      "description": "OK — `{ ok: true, data: … }`",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     }
    },
    "security": [],
    "x-frevia-scope": "public"
   }
  },
  "/api/v1/services": {
   "get": {
    "operationId": "search_services",
    "summary": "Search services (gigs)",
    "description": "Search live freelance services. Returns price (from), fastest delivery, seller, rating and a link. Then call get_service for packages and extras.",
    "parameters": [
     {
      "name": "q",
      "in": "query",
      "required": false,
      "description": "Keywords, e.g. 'logo design' or 'shopify store'.",
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "category",
      "in": "query",
      "required": false,
      "description": "Category slug from list_categories.",
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "max_price",
      "in": "query",
      "required": false,
      "description": "Maximum starting price in the service currency (e.g. 50 = 50.00).",
      "schema": {
       "type": "number"
      }
     },
     {
      "name": "max_days",
      "in": "query",
      "required": false,
      "description": "Only services that can deliver within this many days.",
      "schema": {
       "type": "integer"
      }
     },
     {
      "name": "min_rating",
      "in": "query",
      "required": false,
      "description": "Minimum average rating 1–5.",
      "schema": {
       "type": "number"
      }
     },
     {
      "name": "sort",
      "in": "query",
      "required": false,
      "description": "Sort order.",
      "schema": {
       "type": "string",
       "enum": [
        "newest",
        "price_asc",
        "price_desc",
        "rating"
       ]
      }
     },
     {
      "name": "page",
      "in": "query",
      "required": false,
      "description": "Page number, starting at 1.",
      "schema": {
       "type": "integer"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "OK — `{ ok: true, data: … }`",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     }
    },
    "security": [],
    "x-frevia-scope": "public"
   }
  },
  "/api/v1/services/{id}": {
   "get": {
    "operationId": "get_service",
    "summary": "Get a service",
    "description": "Full details of one live service: description, Basic/Standard/Premium packages (price, delivery days, revisions), paid extras (by index), FAQ, requirement questions, seller and recent reviews.",
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "description": "Service id.",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "OK — `{ ok: true, data: … }`",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     }
    },
    "security": [],
    "x-frevia-scope": "public"
   }
  },
  "/api/v1/jobs": {
   "get": {
    "operationId": "search_jobs",
    "summary": "Search open jobs",
    "description": "Search jobs that clients have posted (for freelancers looking for work).",
    "parameters": [
     {
      "name": "q",
      "in": "query",
      "required": false,
      "description": "Keywords.",
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "category",
      "in": "query",
      "required": false,
      "description": "Category slug.",
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "page",
      "in": "query",
      "required": false,
      "description": "Page number, starting at 1.",
      "schema": {
       "type": "integer"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "OK — `{ ok: true, data: … }`",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     }
    },
    "security": [],
    "x-frevia-scope": "public"
   }
  },
  "/api/v1/me": {
   "get": {
    "operationId": "whoami",
    "summary": "Who am I",
    "description": "The Frevia account this API key acts for: name, roles and the key's scopes.",
    "responses": {
     "200": {
      "description": "OK — `{ ok: true, data: … }`",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ],
    "x-frevia-scope": "read"
   }
  },
  "/api/v1/orders": {
   "post": {
    "operationId": "create_order",
    "summary": "Order a service",
    "description": "Place an order for a service package (and optional extras). The order starts as awaiting_payment and the response has a payUrl: give that link to the user so they pay securely on Frevia (card, PayPal or DuitNow). Agents never handle card details. Money is held in escrow until the user accepts the delivery.",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "service_id": {
          "type": "string",
          "description": "Service id from search_services/get_service."
         },
         "tier": {
          "type": "string",
          "description": "Package tier.",
          "enum": [
           "basic",
           "standard",
           "premium"
          ]
         },
         "extras": {
          "type": "array",
          "description": "Indexes of paid extras from get_service.",
          "items": {
           "type": "integer"
          }
         },
         "requirements": {
          "type": "string",
          "description": "Optional brief for the seller (answers to requirement questions). Can also be sent later."
         }
        },
        "required": [
         "service_id",
         "tier"
        ]
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "OK — `{ ok: true, data: … }`",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ],
    "x-frevia-scope": "order"
   },
   "get": {
    "operationId": "list_orders",
    "summary": "List my orders",
    "description": "Orders where this account is the buyer (as=client) or the seller (as=freelancer).",
    "parameters": [
     {
      "name": "as",
      "in": "query",
      "required": false,
      "description": "Which side.",
      "schema": {
       "type": "string",
       "enum": [
        "client",
        "freelancer"
       ]
      }
     },
     {
      "name": "status",
      "in": "query",
      "required": false,
      "description": "Tab filter.",
      "schema": {
       "type": "string",
       "enum": [
        "priority",
        "active",
        "incomplete",
        "late",
        "delivered",
        "completed",
        "cancelled",
        "disputed",
        "starred"
       ]
      }
     },
     {
      "name": "q",
      "in": "query",
      "required": false,
      "description": "Search by title or code.",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "OK — `{ ok: true, data: … }`",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ],
    "x-frevia-scope": "read"
   }
  },
  "/api/v1/orders/{id}": {
   "get": {
    "operationId": "get_order",
    "summary": "Get an order",
    "description": "One order with its timeline and deliveries (messages, links).",
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "description": "Order id.",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "OK — `{ ok: true, data: … }`",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ],
    "x-frevia-scope": "read"
   }
  },
  "/api/v1/orders/{id}/requirements": {
   "post": {
    "operationId": "submit_requirements",
    "summary": "Send requirements",
    "description": "Buyer: send the brief/answers the seller needs to start.",
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "description": "Order id.",
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "text": {
          "type": "string",
          "description": "The brief."
         }
        },
        "required": [
         "text"
        ]
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "OK — `{ ok: true, data: … }`",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ],
    "x-frevia-scope": "order"
   }
  },
  "/api/v1/orders/{id}/accept": {
   "post": {
    "operationId": "accept_delivery",
    "summary": "Accept delivery",
    "description": "Buyer: accept a delivered order. This completes it and releases the escrowed payment to the seller — only do this when the user has confirmed they are happy.",
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "description": "Order id.",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "OK — `{ ok: true, data: … }`",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ],
    "x-frevia-scope": "order"
   }
  },
  "/api/v1/orders/{id}/revision": {
   "post": {
    "operationId": "request_revision",
    "summary": "Request a revision",
    "description": "Buyer: ask the seller to change a delivered order (uses one of the package's revisions).",
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "description": "Order id.",
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "note": {
          "type": "string",
          "description": "What should change."
         }
        },
        "required": [
         "note"
        ]
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "OK — `{ ok: true, data: … }`",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ],
    "x-frevia-scope": "order"
   }
  },
  "/api/v1/orders/{id}/deliver": {
   "post": {
    "operationId": "deliver_order",
    "summary": "Deliver an order",
    "description": "Seller: deliver work on an in-progress order with a message and up to 10 links.",
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "description": "Order id.",
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "message": {
          "type": "string",
          "description": "Delivery note."
         },
         "links": {
          "type": "array",
          "description": "http(s) links to the work.",
          "items": {
           "type": "string"
          }
         }
        },
        "required": [
         "message"
        ]
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "OK — `{ ok: true, data: … }`",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ],
    "x-frevia-scope": "work"
   }
  },
  "/api/v1/jobs/{id}/proposals": {
   "post": {
    "operationId": "submit_proposal",
    "summary": "Send a proposal",
    "description": "Freelancer: apply to an open job with a cover letter, bid and delivery time.",
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "description": "Job id.",
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "cover_letter": {
          "type": "string",
          "description": "Why you're a fit (50+ characters)."
         },
         "bid": {
          "type": "number",
          "description": "Your price in the job currency."
         },
         "delivery_days": {
          "type": "integer",
          "description": "Days to deliver."
         }
        },
        "required": [
         "cover_letter",
         "bid",
         "delivery_days"
        ]
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "OK — `{ ok: true, data: … }`",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ],
    "x-frevia-scope": "work"
   }
  },
  "/api/v1/services/{id}/contact": {
   "post": {
    "operationId": "contact_seller",
    "summary": "Message a seller",
    "description": "Start (or continue) a conversation with the seller of a service before ordering, and send a first message.",
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "description": "Service id.",
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "message": {
          "type": "string",
          "description": "Your message."
         }
        },
        "required": [
         "message"
        ]
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "OK — `{ ok: true, data: … }`",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ],
    "x-frevia-scope": "message"
   }
  },
  "/api/v1/conversations": {
   "get": {
    "operationId": "list_conversations",
    "summary": "List conversations",
    "description": "Inbox: conversations with last message and unread count.",
    "parameters": [
     {
      "name": "as",
      "in": "query",
      "required": false,
      "description": "Which side.",
      "schema": {
       "type": "string",
       "enum": [
        "client",
        "freelancer"
       ]
      }
     }
    ],
    "responses": {
     "200": {
      "description": "OK — `{ ok: true, data: … }`",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ],
    "x-frevia-scope": "read"
   }
  },
  "/api/v1/conversations/{id}": {
   "get": {
    "operationId": "get_conversation",
    "summary": "Read a conversation",
    "description": "All messages in one conversation (marks it read).",
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "description": "Conversation id.",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "OK — `{ ok: true, data: … }`",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ],
    "x-frevia-scope": "read"
   }
  },
  "/api/v1/conversations/{id}/messages": {
   "post": {
    "operationId": "send_message",
    "summary": "Send a message",
    "description": "Reply in a conversation. Sharing phone numbers, emails or off-site payment details is blocked by marketplace rules.",
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "description": "Conversation id.",
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "body": {
          "type": "string",
          "description": "Message text."
         }
        },
        "required": [
         "body"
        ]
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "OK — `{ ok: true, data: … }`",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ],
    "x-frevia-scope": "message"
   }
  },
  "/api/v1/services/{id}/save": {
   "post": {
    "operationId": "save_service",
    "summary": "Save to list",
    "description": "Heart (save) or un-save a service in the user's list.",
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "description": "Service id.",
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "required": false,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "saved": {
          "type": "boolean",
          "description": "true to save (default), false to remove."
         }
        },
        "required": []
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "OK — `{ ok: true, data: … }`",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ],
    "x-frevia-scope": "read"
   }
  },
  "/api/v1/saved": {
   "get": {
    "operationId": "list_saved",
    "summary": "My saved services",
    "description": "Services the user has saved (hearted).",
    "parameters": [
     {
      "name": "page",
      "in": "query",
      "required": false,
      "description": "Page number, starting at 1.",
      "schema": {
       "type": "integer"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "OK — `{ ok: true, data: … }`",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ],
    "x-frevia-scope": "read"
   }
  }
 }
}