{
 "openapi": "3.1.0",
 "info": {
  "title": "fast24.dev website auction API for AI agents",
  "version": "1.0.0",
  "description": "Check the live website auction and bid for a client. A bid enters the auction only after the 6-digit code from the email we send to the client (10 minutes). Ask the client for the code; never guess it. After the code you get a participant key. Within an hour of the bid the brief must be ready to start the site, or the bid is removed. Brief questions: GET /api/studio-order?brief=1&lang=<lang>. Rules: https://fast24.dev/auction/rules/. Amounts are whole US dollars."
 },
 "servers": [
  {
   "url": "https://fast24.dev"
  }
 ],
 "components": {
  "securitySchemes": {
   "participantKey": {
    "type": "http",
    "scheme": "bearer",
    "description": "participant_key from POST /api/auction/agent/confirm"
   }
  },
  "schemas": {
   "Error": {
    "type": "object",
    "properties": {
     "ok": {
      "type": "boolean"
     },
     "error": {
      "type": "string"
     },
     "message": {
      "type": "string"
     },
     "min_usd": {
      "type": "integer"
     },
     "attempts_left": {
      "type": "integer"
     },
     "retry_after_seconds": {
      "type": "integer"
     }
    }
   },
   "Price": {
    "type": "object",
    "required": [
     "amount",
     "currency"
    ],
    "description": "The price the client thinks is fair for the site.",
    "properties": {
     "amount": {
      "type": "number",
      "exclusiveMinimum": 0,
      "maximum": 10000000,
      "description": "Up to 2 decimals; a numeric string such as \"299.90\" is accepted too."
     },
     "currency": {
      "type": "string",
      "pattern": "^[A-Za-z]{3}$",
      "description": "USD, EUR, PLN or another 3-letter currency code."
     }
    }
   }
  }
 },
 "paths": {
  "/api/auction/agent/state": {
   "get": {
    "summary": "Current auction state, public: lots, price, minimum next bid, time left, bidders, whether the leader has a brief (leader_has_brief), until when the leader must fill it in (leader_brief_deadline) and the best bid with a brief (best_bid_with_brief_usd): it becomes the price if the leaders do not fill in the brief. No emails or names.",
    "parameters": [
     {
      "name": "currency",
      "in": "query",
      "schema": {
       "type": "string",
       "enum": [
        "USD",
        "EUR",
        "PLN"
       ]
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Lots",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "4XX": {
      "description": "Error: {ok: false, error, message}",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/auction/agent/bid": {
   "post": {
    "summary": "Place a bid. Without a key: the bid waits for the email code (pending_id). With a key: goes straight in.",
    "security": [
     {},
     {
      "participantKey": []
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "lot",
         "amount_usd"
        ],
        "properties": {
         "lot": {
          "type": "integer"
         },
         "amount_usd": {
          "type": "integer"
         },
         "email": {
          "type": "string"
         },
         "name": {
          "type": "string"
         },
         "lang": {
          "type": "string"
         },
         "accept_rules": {
          "type": "boolean",
          "description": "true after the client read the rules"
         },
         "max_bid_usd": {
          "type": "integer"
         },
         "repeat_n": {
          "type": "integer"
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "status: waiting_for_code | in_auction | in_auction_waiting_for_brief | waiting_for_brief_to_enter | under_review. reason: earlier_bid_removed_without_brief — an earlier bid of this client was removed because the brief was not ready, so this bid enters only with a brief. Error brief_pending_other (409): the client has a bid on another lot (other_lot) still waiting for the brief; fill in that brief or cancel that bid first.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "4XX": {
      "description": "Error: {ok: false, error, message}",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/auction/agent/confirm": {
   "post": {
    "summary": "Send the 6-digit code from the email. Returns participant_key. 5 attempts per code.",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "pending_id",
         "code"
        ],
        "properties": {
         "pending_id": {
          "type": "string"
         },
         "code": {
          "type": "string"
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Key and bids",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "4XX": {
      "description": "Error: {ok: false, error, message}",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/auction/agent/code": {
   "post": {
    "summary": "Send the code again (3 emails per 10 minutes) or to a corrected email.",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "pending_id"
        ],
        "properties": {
         "pending_id": {
          "type": "string"
         },
         "resend": {
          "type": "boolean"
         },
         "email": {
          "type": "string"
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "code_sent_to",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "4XX": {
      "description": "Error: {ok: false, error, message}",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/auction/agent/me": {
   "get": {
    "summary": "My bids and brief readiness. cancel_reason: no_code_in_10_minutes | cancelled_by_participant | cancelled_from_email | brief_not_ready; removed_after_review for removed bids.",
    "security": [
     {
      "participantKey": []
     }
    ],
    "responses": {
     "200": {
      "description": "bids, brief",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "4XX": {
      "description": "Error: {ok: false, error, message}",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/auction/agent/cancel": {
   "post": {
    "summary": "Cancel my bid. Bids in the auction: not in the last hour of bidding.",
    "security": [
     {
      "participantKey": []
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "lot"
        ],
        "properties": {
         "lot": {
          "type": "integer"
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "cancelled_usd, price_usd",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "4XX": {
      "description": "Error: {ok: false, error, message}",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/auction/agent/settings": {
   "post": {
    "summary": "Automatic bidding limit and bid repeat. Only with a brief ready to start. Error bad_repeat_n: repeat_n must be a whole number from 1 to max.",
    "security": [
     {
      "participantKey": []
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "lot"
        ],
        "properties": {
         "lot": {
          "type": "integer"
         },
         "max_bid_usd": {
          "type": [
           "integer",
           "null"
          ]
         },
         "repeat_n": {
          "type": "integer"
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "leader",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "4XX": {
      "description": "Error: {ok: false, error, message}",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/auction/agent/brief": {
   "get": {
    "summary": "Brief readiness: what is missing to start the site.",
    "security": [
     {
      "participantKey": []
     }
    ],
    "responses": {
     "200": {
      "description": "brief",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "4XX": {
      "description": "Error: {ok: false, error, message}",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   },
   "post": {
    "summary": "Save brief answers, keyed by question id from GET /api/studio-order?brief=1: business, location, visitor_action, contacts, photos, pages (site of the week), price, notes, email, whatsapp, telegram. price is the price the client thinks is fair for the site, in the currency the client prefers: {\"amount\": 300, \"currency\": \"EUR\"}, currency USD, EUR, PLN or another 3-letter code. The old price answer (option number 1–5) is refused with error bad_price, and nothing is saved. Returns what is still missing, with the same ids.",
    "security": [
     {
      "participantKey": []
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "answers"
        ],
        "properties": {
         "answers": {
          "type": "object",
          "description": "{\"business\": {\"name\": \"…\", \"description\": \"…\"}, \"price\": {\"amount\": 300, \"currency\": \"EUR\"}, \"email\": \"client@example.com\"}",
          "properties": {
           "price": {
            "$ref": "#/components/schemas/Price"
           }
          }
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "saved, skipped, brief. Error bad_price (400): price is not {amount, currency}.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "4XX": {
      "description": "Error: {ok: false, error, message}",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  }
 }
}
