{"openapi": "3.1.0", "info": {"title": "BuySecure Public API", "version": "1.0.0", "description": "Create and monitor BuySecure contract reviews in the production environment without Auth0, a Partner API key, a bearer token, or a separate per-review access secret. BuySecure provides structured legal information, not legal advice. Before uploading a contract or submitting buyer personal information, show the buyer https://buysecure.com.au/terms and https://buysecure.com.au/privacy and obtain explicit acceptance of both. Never consent on the buyer's behalf. The review UUID is the intentional access handle for Public API reviews and must be treated as sensitive. The API returns workflow, payment, and hosted handoff metadata only; it never returns findings or report content as machine-readable JSON, even after payment."}, "externalDocs": {"description": "Agent-readable workflow, consent, safety, and legal-information instructions", "url": "https://buysecure.com.au/docs/public-api.md"}, "servers": [{"url": "https://api.buysecure.com.au"}], "security": [], "tags": [{"name": "Public reviews", "description": "Unauthenticated UUID-addressed contract review workflow. Poll every 15 seconds while processing and every 5-15 seconds after payment. Respect Retry-After when present; after HTTP 429, wait at least 30 seconds and increase the retry delay. Platform throttling is not caller authentication."}], "paths": {"/public/reviews/upload-path": {"get": {"tags": ["Public reviews"], "operationId": "getPublicReviewUploadPath", "summary": "Request a PDF upload form", "description": "Returns a short-lived S3-style form for uploading one PDF before creating a review. First include every returned fields entry unchanged in a multipart POST to the returned url, then append the PDF using the form field name file and content type application/pdf. A successful upload normally returns HTTP 204. Treat the returned URL and all form fields as opaque sensitive values and do not log them.", "responses": {"200": {"description": "Upload form created.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UploadPathResponse"}}}}, "500": {"$ref": "#/components/responses/InternalServerError"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}}}, "/public/reviews": {"post": {"tags": ["Public reviews"], "operationId": "createPublicReview", "summary": "Create a Public API review", "description": "Creates a locked, unpaid BuySecure review from a completed public upload. Before uploading or submitting buyer personal information, the agent must show the Terms and Conditions and Privacy Policy URLs documented in the API description and obtain the buyer's explicit acceptance of both. Set termsOfService to true only after that acceptance; never consent on the buyer's behalf. Reuse both pdfFile and idempotencyKey when retrying the same request. The response contains status and hosted handoff metadata, never findings, contract metadata, or report content.", "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/CreatePublicReviewRequest"}, "example": {"firstName": "<buyer-first-name>", "lastName": "<buyer-last-name>", "email": "<buyer-email>", "phone": "<buyer-phone>", "termsOfService": true, "pdfFile": "public/00000000-0000-4000-8000-000000000000/contract.pdf", "idempotencyKey": "<caller-generated-retry-key>", "region": "au"}}}}, "responses": {"200": {"description": "An existing review was returned for an idempotent retry.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/CreatePublicReviewResponse"}, "example": {"reviewId": "00000000-0000-4000-8000-000000000001", "reviewUrl": "https://buysecure.com.au/reviews/00000000-0000-4000-8000-000000000001", "status": "new", "progress": 0, "progressText": null, "createdAt": 1710812400, "modifiedAt": 1710812400, "source": "public_api", "idempotencyKey": "<caller-generated-retry-key>"}}}}, "201": {"description": "Review created.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/CreatePublicReviewResponse"}, "example": {"reviewId": "00000000-0000-4000-8000-000000000001", "reviewUrl": "https://buysecure.com.au/reviews/00000000-0000-4000-8000-000000000001", "status": "new", "progress": 0, "progressText": null, "createdAt": 1710812400, "modifiedAt": 1710812400, "source": "public_api", "idempotencyKey": "<caller-generated-retry-key>"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "500": {"$ref": "#/components/responses/InternalServerError"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}}}, "/public/reviews/{reviewId}": {"get": {"tags": ["Public reviews"], "operationId": "getPublicReview", "summary": "Poll Public API review status", "description": "Returns status, progress, payment state, and BuySecure-hosted handoff URLs for a Public API review. Poll every 15 seconds while status is new or processing. When a completed review is unpaid, send the user to paymentUrl so the BuySecure-hosted page can show the required acknowledgement before creating checkout. After the user pays, continue polling every 5-15 seconds until paid is true, then open reviewUrl or retrieve the PDF. Respect Retry-After; after HTTP 429, wait at least 30 seconds and increase the retry delay. The response never contains findings, disclosures, contract metadata, report sections, evidence, or report JSON, whether paid or unpaid.", "parameters": [{"$ref": "#/components/parameters/ReviewId"}], "responses": {"200": {"description": "Current status and hosted handoff metadata.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PublicReviewStatusResponse"}, "examples": {"processing": {"summary": "Review analysis is in progress", "value": {"reviewId": "00000000-0000-4000-8000-000000000001", "status": "processing", "progress": 55, "progressText": "Reviewing contract", "createdAt": 1710812400, "modifiedAt": 1710812600, "paid": false, "locked": false, "checkoutRequired": false, "checkoutAvailable": false, "reviewUrl": "https://buysecure.com.au/reviews/00000000-0000-4000-8000-000000000001"}}, "completedUnpaid": {"summary": "Review is complete and requires payment", "value": {"reviewId": "00000000-0000-4000-8000-000000000001", "status": "completed", "progress": 100, "progressText": "Review complete", "createdAt": 1710812400, "modifiedAt": 1710812700, "paid": false, "locked": true, "checkoutRequired": true, "checkoutAvailable": true, "reviewUrl": "https://buysecure.com.au/reviews/00000000-0000-4000-8000-000000000001", "paymentUrl": "https://buysecure.com.au/reviews/00000000-0000-4000-8000-000000000001/payment-link", "address": "<property-address>"}}, "completedPaid": {"summary": "Payment is confirmed and the report is available", "value": {"reviewId": "00000000-0000-4000-8000-000000000001", "status": "completed", "progress": 100, "progressText": "Review complete", "createdAt": 1710812400, "modifiedAt": 1710812800, "paid": true, "locked": false, "checkoutRequired": false, "checkoutAvailable": false, "reviewUrl": "https://buysecure.com.au/reviews/00000000-0000-4000-8000-000000000001"}}, "failed": {"summary": "Review processing failed with a sanitized reason", "value": {"reviewId": "00000000-0000-4000-8000-000000000001", "status": "failed", "progress": 40, "progressText": "Review failed", "createdAt": 1710812400, "modifiedAt": 1710812650, "paid": false, "locked": false, "checkoutRequired": false, "checkoutAvailable": false, "reviewUrl": "https://buysecure.com.au/reviews/00000000-0000-4000-8000-000000000001", "failCode": "NOT_SUPPORTED", "failReason": "This contract is not currently supported."}}}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "404": {"$ref": "#/components/responses/ReviewNotFound"}, "500": {"$ref": "#/components/responses/InternalServerError"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}}}, "/public/reviews/{reviewId}/pdf": {"get": {"tags": ["Public reviews"], "operationId": "getPublicReviewPdf", "summary": "Retrieve the paid BuySecure PDF", "description": "Generates the standard BuySecure-themed PDF as a legal-information report for a completed Public API review only after payment is confirmed. Describe it as a BuySecure contract review, never legal advice, a solicitor's review, a white-labelled report, or another provider's report. When summarising it, attribute statements to the BuySecure report, preserve qualifications, cite the relevant heading or page when possible, and do not add legal conclusions or change risk ratings. If the user requests a legal opinion, state exactly: This is general information only and is not legal advice. For advice tailored to your circumstances, speak with a qualified Australian lawyer or conveyancer. For human assistance, recommend Lawlab at https://www.lawlab.com.au/contact, 1800 529 522, or conveyancing@lawlab.com.au. The temporary download URL is sensitive bearer material and must not be logged.", "parameters": [{"$ref": "#/components/parameters/ReviewId"}], "responses": {"200": {"description": "A short-lived URL for the paid BuySecure PDF.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PublicPdfResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "402": {"description": "Payment is required before the PDF is available.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PublicApiError"}}}}, "404": {"$ref": "#/components/responses/ReviewNotFound"}, "409": {"description": "The review is still processing or has failed.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PublicApiError"}}}}, "500": {"$ref": "#/components/responses/InternalServerError"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}}}}, "components": {"parameters": {"ReviewId": {"name": "reviewId", "in": "path", "required": true, "description": "Canonical UUID returned when the Public API review was created. Knowing this UUID is sufficient to access the Public API workflow for that review.", "schema": {"type": "string", "format": "uuid"}}}, "responses": {"BadRequest": {"description": "The request is malformed or fails validation.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PublicApiError"}}}}, "ReviewNotFound": {"description": "The review was not found or was not created through the Public API.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PublicApiError"}}}}, "InternalServerError": {"description": "The request could not be completed. Internal service details are not returned.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PublicApiError"}}}}, "TooManyRequests": {"description": "The caller is polling or submitting too quickly. Respect Retry-After when present, wait at least 30 seconds, and increase the delay before retrying.", "headers": {"Retry-After": {"description": "When present, the minimum time to wait before retrying, expressed as delta-seconds or an HTTP date.", "schema": {"type": "string"}}}, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PublicApiError"}}}}}, "schemas": {"UploadPathResponse": {"type": "object", "additionalProperties": false, "required": ["uploadId", "pdfFile", "url", "fields", "expiresIn", "maxSizeBytes"], "properties": {"uploadId": {"type": "string", "format": "uuid", "description": "Identifier for this upload. It is not the review UUID."}, "pdfFile": {"type": "string", "description": "Public upload object key that must be passed unchanged when creating the review.", "pattern": "^public/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/contract\\.pdf$"}, "url": {"type": "string", "format": "uri", "description": "Opaque destination for the multipart PDF upload. POST directly to this URL rather than to the BuySecure API."}, "fields": {"type": "object", "description": "Opaque form fields that must be included unchanged before the multipart file field and must not be logged.", "additionalProperties": {"type": "string"}}, "expiresIn": {"type": "integer", "minimum": 1, "description": "Upload form lifetime in seconds."}, "maxSizeBytes": {"type": "integer", "const": 52428800, "description": "Maximum accepted PDF size in bytes."}}}, "CreatePublicReviewRequest": {"type": "object", "additionalProperties": false, "required": ["firstName", "lastName", "email", "phone", "termsOfService", "pdfFile", "idempotencyKey"], "properties": {"firstName": {"type": "string", "minLength": 1, "description": "Buyer first name."}, "lastName": {"type": "string", "minLength": 1, "description": "Buyer last name."}, "email": {"type": "string", "format": "email", "minLength": 1, "description": "Buyer email address. Do not log this value."}, "phone": {"type": "string", "minLength": 1, "description": "Buyer phone number. Prefer an international format such as +61 400 000 000 for Australia or +64 21 000 0000 for New Zealand. Do not log this value."}, "termsOfService": {"type": "boolean", "const": true, "description": "Set to true only after the buyer explicitly confirms that they have read and accept both https://buysecure.com.au/terms and https://buysecure.com.au/privacy. Never set this on the buyer's behalf."}, "pdfFile": {"type": "string", "description": "Public upload object key returned by the upload-path operation.", "pattern": "^public/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/contract\\.pdf$"}, "region": {"type": "string", "enum": ["au", "nz"], "description": "Optional buyer region. Use au for Australia or nz for New Zealand; jurisdiction is still derived from the contract."}, "idempotencyKey": {"type": "string", "minLength": 1, "maxLength": 300, "description": "Caller-generated retry key. Reuse it with the same pdfFile when retrying the same request."}}}, "CreatePublicReviewResponse": {"type": "object", "additionalProperties": false, "required": ["reviewId", "reviewUrl", "status", "progress", "progressText", "createdAt", "modifiedAt", "source", "idempotencyKey"], "properties": {"reviewId": {"type": "string", "format": "uuid", "description": "Public handle used for polling, hosted payment, paid PDF retrieval, and the hosted review experience."}, "reviewUrl": {"type": "string", "format": "uri", "description": "BuySecure-hosted review experience."}, "status": {"type": "string", "enum": ["new", "processing", "completed", "failed"], "description": "Current workflow status."}, "progress": {"type": "number", "minimum": 0, "maximum": 100}, "progressText": {"type": ["string", "null"]}, "createdAt": {"type": ["number", "null"], "description": "Creation time as Unix epoch seconds."}, "modifiedAt": {"type": ["number", "null"], "description": "Last modification time as Unix epoch seconds."}, "source": {"type": "string", "const": "public_api"}, "idempotencyKey": {"type": ["string", "null"]}}}, "PublicReviewStatusResponse": {"description": "Exactly one workflow state. While new or processing, keep polling. When completed and unpaid, paymentUrl is required and must be presented to the buyer. When completed and paid, the report is available. When failed, failReason is a sanitized public message.", "oneOf": [{"$ref": "#/components/schemas/PublicReviewProcessingStatus"}, {"$ref": "#/components/schemas/PublicReviewCompletedUnpaidStatus"}, {"$ref": "#/components/schemas/PublicReviewCompletedPaidStatus"}, {"$ref": "#/components/schemas/PublicReviewFailedStatus"}]}, "PublicReviewProcessingStatus": {"title": "Public review processing status", "type": "object", "additionalProperties": false, "required": ["reviewId", "status", "progress", "progressText", "createdAt", "modifiedAt", "paid", "locked", "checkoutRequired", "checkoutAvailable", "reviewUrl"], "properties": {"reviewId": {"type": "string", "format": "uuid"}, "status": {"type": "string", "enum": ["new", "processing"], "description": "The review is still being processed. Poll every 15 seconds."}, "progress": {"type": "number", "minimum": 0, "maximum": 100}, "progressText": {"type": ["string", "null"]}, "createdAt": {"type": ["number", "null"], "description": "Creation time as Unix epoch seconds."}, "modifiedAt": {"type": ["number", "null"], "description": "Last modification time as Unix epoch seconds."}, "paid": {"type": "boolean", "enum": [false]}, "locked": {"type": "boolean", "enum": [false], "deprecated": true, "description": "Always equals checkoutRequired. Use checkoutRequired."}, "checkoutRequired": {"type": "boolean", "enum": [false], "description": "Canonical payment signal. False while processing."}, "checkoutAvailable": {"type": "boolean", "enum": [false], "deprecated": true, "description": "Always equals checkoutRequired. Use checkoutRequired."}, "reviewUrl": {"type": "string", "format": "uri", "description": "Sensitive BuySecure-hosted review experience. Disclose only to the buyer who initiated this review."}}}, "PublicReviewCompletedUnpaidStatus": {"title": "Public review completed and unpaid status", "type": "object", "additionalProperties": false, "required": ["reviewId", "status", "progress", "progressText", "createdAt", "modifiedAt", "paid", "locked", "checkoutRequired", "checkoutAvailable", "reviewUrl", "paymentUrl"], "properties": {"reviewId": {"type": "string", "format": "uuid"}, "status": {"type": "string", "enum": ["completed"], "description": "Processing is complete, but payment is still required. Present paymentUrl, then continue polling after payment."}, "progress": {"type": "number", "minimum": 0, "maximum": 100}, "progressText": {"type": ["string", "null"]}, "createdAt": {"type": ["number", "null"], "description": "Creation time as Unix epoch seconds."}, "modifiedAt": {"type": ["number", "null"], "description": "Last modification time as Unix epoch seconds."}, "paid": {"type": "boolean", "enum": [false]}, "locked": {"type": "boolean", "enum": [true], "deprecated": true, "description": "Always equals checkoutRequired. Use checkoutRequired."}, "checkoutRequired": {"type": "boolean", "enum": [true], "description": "Canonical payment signal. Present paymentUrl when true."}, "checkoutAvailable": {"type": "boolean", "enum": [true], "deprecated": true, "description": "Always equals checkoutRequired. Use checkoutRequired."}, "reviewUrl": {"type": "string", "format": "uri", "description": "Sensitive BuySecure-hosted review experience. Disclose only to the buyer who initiated this review."}, "paymentUrl": {"type": "string", "format": "uri", "description": "Sensitive BuySecure-hosted acknowledgement and payment page. Present this URL to the buyer; do not create checkout directly."}, "address": {"type": "string", "description": "Property address, included only when known so the buyer can confirm the review before payment."}}}, "PublicReviewCompletedPaidStatus": {"title": "Public review completed and paid status", "type": "object", "additionalProperties": false, "required": ["reviewId", "status", "progress", "progressText", "createdAt", "modifiedAt", "paid", "locked", "checkoutRequired", "checkoutAvailable", "reviewUrl"], "properties": {"reviewId": {"type": "string", "format": "uuid"}, "status": {"type": "string", "enum": ["completed"], "description": "Processing and payment are complete. Open reviewUrl or retrieve the paid PDF."}, "progress": {"type": "number", "minimum": 0, "maximum": 100}, "progressText": {"type": ["string", "null"]}, "createdAt": {"type": ["number", "null"], "description": "Creation time as Unix epoch seconds."}, "modifiedAt": {"type": ["number", "null"], "description": "Last modification time as Unix epoch seconds."}, "paid": {"type": "boolean", "enum": [true]}, "locked": {"type": "boolean", "enum": [false], "deprecated": true, "description": "Always equals checkoutRequired. Use checkoutRequired."}, "checkoutRequired": {"type": "boolean", "enum": [false], "description": "Canonical payment signal. False after payment is confirmed."}, "checkoutAvailable": {"type": "boolean", "enum": [false], "deprecated": true, "description": "Always equals checkoutRequired. Use checkoutRequired."}, "reviewUrl": {"type": "string", "format": "uri", "description": "Sensitive BuySecure-hosted review experience. Disclose only to the buyer who initiated this review."}}}, "PublicReviewFailedStatus": {"title": "Public review failed status", "type": "object", "additionalProperties": false, "required": ["reviewId", "status", "progress", "progressText", "createdAt", "modifiedAt", "paid", "locked", "checkoutRequired", "checkoutAvailable", "reviewUrl", "failCode", "failReason"], "properties": {"reviewId": {"type": "string", "format": "uuid"}, "status": {"type": "string", "enum": ["failed"], "description": "Processing failed. Stop polling and present only the sanitized failReason."}, "progress": {"type": "number", "minimum": 0, "maximum": 100}, "progressText": {"type": ["string", "null"]}, "createdAt": {"type": ["number", "null"], "description": "Creation time as Unix epoch seconds."}, "modifiedAt": {"type": ["number", "null"], "description": "Last modification time as Unix epoch seconds."}, "paid": {"type": "boolean"}, "locked": {"type": "boolean", "enum": [false], "deprecated": true, "description": "Always equals checkoutRequired. Use checkoutRequired."}, "checkoutRequired": {"type": "boolean", "enum": [false], "description": "Canonical payment signal. False after processing fails."}, "checkoutAvailable": {"type": "boolean", "enum": [false], "deprecated": true, "description": "Always equals checkoutRequired. Use checkoutRequired."}, "reviewUrl": {"type": "string", "format": "uri", "description": "Sensitive BuySecure-hosted review experience. Disclose only to the buyer who initiated this review."}, "failCode": {"type": ["string", "null"], "description": "Public failure category when one is available."}, "failReason": {"type": "string", "description": "Sanitized public failure description. Do not infer or expose an internal reason."}}}, "PublicPdfResponse": {"type": "object", "additionalProperties": false, "required": ["reviewId", "status", "downloadUrl", "expiresIn"], "properties": {"reviewId": {"type": "string", "format": "uuid"}, "status": {"type": "string", "const": "completed"}, "downloadUrl": {"type": "string", "format": "uri", "description": "Sensitive short-lived URL for the paid standard BuySecure legal-information PDF. Disclose only to the buyer who initiated this review and do not persist it beyond the current task."}, "expiresIn": {"type": "integer", "const": 3600, "description": "Download URL lifetime in seconds."}}}, "PublicApiError": {"type": "object", "additionalProperties": false, "required": ["message"], "properties": {"message": {"type": "string"}, "code": {"type": "string", "description": "Stable error code when the response represents a review or payment state."}, "status": {"type": "string"}, "progress": {"type": "number", "minimum": 0, "maximum": 100}, "progressText": {"type": ["string", "null"]}, "failCode": {"type": ["string", "null"]}, "failReason": {"type": "string", "description": "Sanitized public failure description."}}}}}}