openapi: 3.0.3
info:
title: Landmark Conveyancing Experience API
description: "# Overview\n\nThe Conveyancing API is where you quote for, instruct, and manage conveyancing work with Landmark. Whether you're referring work to a panel conveyancer or handling the cases that come your way, you do it through one API and against one shared case record.\n\nThe first thing it supports is panel conveyancing through Optimus: as an **introducer** you create a quote, choose a conveyancer, and instruct them on your client's behalf; as a **conveyancer** you pick up the cases assigned to you and keep the introducer updated as the work moves forward. That's the workflow this documentation focuses on, though the API will grow to cover more of how you connect to conveyancing over time.\n\nThroughout, a quote becomes a case once instructed, both sides share one case record, and you only see the cases your account is party to.\n\n# Availability\n\nFunctionality is being made available in UAT as it becomes ready to test. We'll keep this section updated as each drop lands.\n\nThe **Quotes** and **Cases** endpoints have a settled schema and you can use them as a reference to start your integration work. Endpoints still undergoing final design and build work are marked **Preview** in the reference below — currently **Add Document** and **Retrieve Document**. They're here so you can see where the API is heading, but please don't build against them yet.\n\nYour Landmark contact will confirm what's available to you and when.\n\n# Getting started\n\nThe API is a REST service over HTTPS. You send and receive JSON, apart from document uploads, which use `multipart/form-data`, and PDF or document downloads, which return the file itself.\n\n| Environment | Base URL | Use it for |\n|---|---|---|\n| UAT | `https://uat-api.landmarkcloudservices.com/conveyances` | Building and testing your integration |\n| Production | `https://api.landmarkcloudservices.com/conveyances` | Live cases |\n\nYou'll start with UAT credentials, then move to production once your integration is ready to go live.\n\n## Authentication\n\nThe API uses OAuth 2.0 with the client credentials grant. When you're onboarded you'll receive a client ID and secret. These identify your account, so there's no separate account header to send.\n\n**1. Get an access token** by POSTing your credentials to the token endpoint for your environment:\n\n- UAT: `https://lmkmaster-uat.eu.auth0.com/oauth/token`\n- Production: `https://lmkmaster.eu.auth0.com/oauth/token`\n\n```json\n{\n \"client_id\": \"your-client-id\",\n \"client_secret\": \"your-client-secret\",\n \"audience\": \"https://api.landmarkcloudservices.com\",\n \"grant_type\": \"client_credentials\"\n}\n```\n\nYou'll get back an `access_token` (a JWT) and an `expires_in` value. Cache and reuse the token until it's close to expiring rather than fetching a new one for every call.\n\n**2. Send the token on every request:**\n\n- `Authorization: Bearer <access_token>`\n\nA `401` means your token is missing or invalid. A `403` means your account isn't entitled to that operation; contact support if you think that's wrong.\n\n## Errors and support\n\nStandard HTTP status codes apply: `400` validation, `401` authentication, `403` not entitled, `404` not found, `429` too many requests, `5xx` server error.\n\nWhen something goes wrong you'll get back a consistent JSON shape:\n\n```json\n{\n \"status\": \"400\",\n \"code\": \"40001\",\n \"title\": \"Validation error\",\n \"messages\": [\n { \"property\": \"propertyAddress.postcode\", \"message\": \"Postcode is required\" }\n ]\n}\n```\n\nEvery response includes a `traceresponse` header that uniquely identifies your request. Quote it when you contact support so we can find it quickly.\n\nSupport Contact: TBC\n"
version: 0.8.1
servers:
- url: https://api.landmarkcloudservices.com/conveyances
description: Production environment
- url: https://uat-api.landmarkcloudservices.com/conveyances
description: Test environment
paths:
/quotes:
post:
summary: Create New Quote
description: 'Create a quote for your client''s transaction. Provide the property address, the applicants, the account roles, and the product details, and you''ll get back the panel conveyancers available to you with their pricing.
**Standalone quote**: provide a single quote request in the `quotes` array.
**Combined sale and purchase**: provide two quote requests in the `quotes` array, one Sale and one Purchase. Each is independent, with its own `productId`, applicants, and product details.
**Accounts**: each quote needs an `accounts` array naming at least one `Originator` and at least one `Introducer`. These can be the same account holding both roles. You''re given these account identifiers when you''re onboarded.
**Contacts**: each quote needs a `contacts` array including the requestor (the person placing the quote on the applicant''s behalf). Identify them with `contactId` or `email`. Only one contact with role `Requestor` is allowed per quote.
**Products**: the `product` object must match one of the [Product Schemas](#tag/Product-Schemas) for the product type and property location you''re quoting for.
'
operationId: conveyances-experience-quote-create
x-external-entitlement: external:conveyancesexperience:quote:create
tags:
- Quotes
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateQuoteRequest'
examples:
standalonePurchase:
$ref: '#/components/examples/StandalonePurchaseQuote'
combinedSaleAndPurchase:
$ref: '#/components/examples/CombinedSaleAndPurchase'
responses:
'201':
description: Quote created successfully
content:
application/json:
schema:
$ref: '#/components/schemas/CreateQuoteResponse'
examples:
standaloneQuote:
summary: Standalone Quote Response
value:
quotes:
- quoteId: 550e8400-e29b-41d4-a716-446655440000
product:
productId: f7a7438b-fe4e-4361-b00b-d3d709a16d01
propertyLocation: EnglandWales
conveyancers:
- conveyancerId: f7a7438b-fe4e-4361-b00b-d3d709a16d01
name: Key Conveyancing LLP
location: Northampton
logoUrl: https://cdn.optimus.com/logos/key-conveyancing.png
overallRating: 4.3
ratingBreakdown:
feedback: 4
complaintRatio: 4
telephoneTime: 5
completionTime: 4
- conveyancerId: b2c3d4e5-f6a7-8901-bcde-f1234567890a
name: O'Neill Patient Solicitors LLP
location: Stockport
logoUrl: https://cdn.optimus.com/logos/oneill-patient.png
overallRating: 2
ratingBreakdown:
feedback: 2
complaintRatio: 2
telephoneTime: 3
completionTime: 2
combinedQuotes:
summary: Combined Sale and Purchase Response
value:
quotes:
- quoteId: 550e8400-e29b-41d4-a716-446655440001
product:
productId: e5e42a0e-6717-4b45-8cd5-0f3a3b79cf4d
propertyLocation: EnglandWales
conveyancers:
- conveyancerId: f7a7438b-fe4e-4361-b00b-d3d709a16d01
name: Key Conveyancing LLP
location: Northampton
logoUrl: https://cdn.optimus.com/logos/key-conveyancing.png
overallRating: 4.3
ratingBreakdown:
feedback: 4
complaintRatio: 4
telephoneTime: 5
completionTime: 4
fee:
totalIncVat: 1250
breakdown:
legalWork:
- description: Legal Work
excVat: 600
vat: 120
incVat: 720
disbursements:
- description: Search Pack
excVat: 300
vat: 60
incVat: 360
supplements: []
- quoteId: 550e8400-e29b-41d4-a716-446655440002
product:
productId: f7a7438b-fe4e-4361-b00b-d3d709a16d01
propertyLocation: EnglandWales
conveyancers:
- conveyancerId: f7a7438b-fe4e-4361-b00b-d3d709a16d01
name: Key Conveyancing LLP
location: Northampton
logoUrl: https://cdn.optimus.com/logos/key-conveyancing.png
overallRating: 4.3
ratingBreakdown:
feedback: 4
complaintRatio: 4
telephoneTime: 5
completionTime: 4
fee:
totalIncVat: 1982.4
breakdown:
legalWork:
- description: Legal Work
excVat: 755
vat: 151
incVat: 906
disbursements:
- description: Search Pack
excVat: 345
vat: 69
incVat: 414
supplements:
- description: Lender Special Conditions
excVat: 250
vat: 50
incVat: 300
'400':
$ref: '#/components/responses/400BadRequest'
'401':
$ref: '#/components/responses/401Unauthorized'
'403':
$ref: '#/components/responses/403Forbidden'
'404':
$ref: '#/components/responses/404NotFound'
'429':
$ref: '#/components/responses/429TooManyRequests'
'500':
$ref: '#/components/responses/500InternalServerError'
get:
summary: List Quotes
description: 'Retrieve your quotes, most recently updated first.
Filter, sort, and page the results with the OData-style query parameters below.
'
operationId: conveyances-experience-quote-list
x-external-entitlement: external:conveyancesexperience:quote:list
tags:
- Quotes
parameters:
- name: $filter
in: query
description: 'OData $filter syntax i.e. $filter=status eq ''Completed'' <br/><br/> Supported $filter values are: ''status'', ''createdDate'', ''updatedDate'', ''productId'''
required: false
schema:
type: string
maxLength: 1000
- name: $orderby
in: query
description: 'OData $orderby syntax i.e. $orderby=updatedDate desc <br/><br/> Supported $orderby values are: ''createdDate'', ''updatedDate'', ''productName'', ''status'''
required: false
schema:
type: string
maxLength: 1000
default: updatedDate desc
- name: $top
in: query
description: The number of items to return
schema:
type: integer
format: int32
minimum: 1
maximum: 999
default: 20
- name: $skip
in: query
description: The number of items to skip
schema:
type: integer
format: int32
minimum: 0
maximum: 9999999
default: 0
- name: $count
in: query
description: Whether or not to return a count of items
schema:
type: boolean
default: false
- name: countOnly
in: query
description: Return only the count of items
schema:
type: boolean
default: false
responses:
'200':
description: List of quotes retrieved successfully
content:
application/json:
schema:
$ref: '#/components/schemas/QuoteListResponse'
examples:
quoteList:
$ref: '#/components/examples/QuoteListResponseExample'
'400':
$ref: '#/components/responses/400BadRequest'
'401':
$ref: '#/components/responses/401Unauthorized'
'403':
$ref: '#/components/responses/403Forbidden'
'404':
$ref: '#/components/responses/404NotFound'
'429':
$ref: '#/components/responses/429TooManyRequests'
'500':
$ref: '#/components/responses/500InternalServerError'
/quotes/{quoteId}:
get:
summary: Retrieve Quote Details
description: 'Retrieve the full details of one of your quotes: the property, applicants, product details, the available conveyancers, and the pricing breakdown.
'
operationId: conveyances-experience-quote-read
x-external-entitlement: external:conveyancesexperience:quote:read
tags:
- Quotes
parameters:
- name: quoteId
in: path
required: true
description: Unique identifier for the quote
schema:
$ref: '#/components/schemas/LgsUuid'
responses:
'200':
description: Quote details retrieved successfully
content:
application/json:
schema:
$ref: '#/components/schemas/RetrieveQuoteResponse'
examples:
retrieveQuote:
$ref: '#/components/examples/RetrieveQuoteResponseExample'
'400':
$ref: '#/components/responses/400BadRequest'
'401':
$ref: '#/components/responses/401Unauthorized'
'403':
$ref: '#/components/responses/403Forbidden'
'404':
$ref: '#/components/responses/404NotFound'
'429':
$ref: '#/components/responses/429TooManyRequests'
'500':
$ref: '#/components/responses/500InternalServerError'
/quotes/{quoteId}/pdf:
get:
summary: Download Quote PDF
description: 'Download a PDF copy of the quote, for example to share with your client.
'
operationId: conveyances-experience-quote-pdf-download
x-external-entitlement: external:conveyancesexperience:quote:pdf:download
tags:
- Quotes
parameters:
- name: quoteId
in: path
required: true
description: Unique identifier for the quote
schema:
$ref: '#/components/schemas/LgsUuid'
example: 550e8400-e29b-41d4-a716-446655440000
responses:
'200':
description: Quote PDF retrieved successfully
headers:
Content-Disposition:
schema:
type: string
maxLength: 1000
pattern: ^attachment; filename=".*"$
description: 'Specifies that the response is an attachment, and includes the filename for the PDF.
'
example: attachment; filename="quote.pdf"
traceresponse:
schema:
type: string
pattern: ^[0-9a-fA-F]{2}-[0-9a-fA-F]{32}--[0-9a-fA-F]{2}$
minLength: 39
maxLength: 39
description: 'Trace context providing a unique identifier for an individual request.
'
example: 00-199c8ce55dc743a88661498aa8eb2cfc--00
content:
application/pdf:
schema:
type: string
format: binary
'400':
$ref: '#/components/responses/400BadRequest'
'401':
$ref: '#/components/responses/401Unauthorized'
'403':
$ref: '#/components/responses/403Forbidden'
'404':
$ref: '#/components/responses/404NotFound'
'429':
$ref: '#/components/responses/429TooManyRequests'
'500':
$ref: '#/components/responses/500InternalServerError'
/quotes/{quoteId}/instruct:
post:
summary: Instruct Quote
description: 'Instruct a quote to turn it into a live case. Supply the `conveyancerId` of the conveyancer you''re choosing in the request body: it must be one of the conveyancers returned for this quote (see `GET /quotes/{quoteId}` or the create-quote response). Instructing creates the case and makes the details available to that conveyancer.
'
operationId: conveyances-experience-quote-instruct
x-external-entitlement: external:conveyancesexperience:quote:instruct
tags:
- Quotes
parameters:
- name: quoteId
in: path
required: true
description: Unique identifier for the quote
schema:
$ref: '#/components/schemas/LgsUuid'
example: 550e8400-e29b-41d4-a716-446655440000
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/InstructQuoteRequest'
responses:
'201':
description: Quote instructed successfully, case created
'400':
$ref: '#/components/responses/400BadRequest'
'401':
$ref: '#/components/responses/401Unauthorized'
'403':
$ref: '#/components/responses/403Forbidden'
'404':
$ref: '#/components/responses/404NotFound'
'429':
$ref: '#/components/responses/429TooManyRequests'
'500':
$ref: '#/components/responses/500InternalServerError'
/quotes/{quoteId}/property-address:
put:
summary: Update Property Address
description: 'Update the property address on a quote. The values you provide replace the current address.
'
operationId: conveyances-experience-quote-address-update
x-external-entitlement: external:conveyancesexperience:quote:propertyaddress:update
tags:
- Quotes
parameters:
- name: quoteId
in: path
required: true
description: Unique identifier for the quote
schema:
$ref: '#/components/schemas/LgsUuid'
example: 550e8400-e29b-41d4-a716-446655440000
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/PropertyAddress'
examples:
updatePropertyAddress:
$ref: '#/components/examples/UpdateQuotePropertyAddressExample'
responses:
'200':
description: Quote property address updated successfully
'400':
$ref: '#/components/responses/400BadRequest'
'401':
$ref: '#/components/responses/401Unauthorized'
'403':
$ref: '#/components/responses/403Forbidden'
'404':
$ref: '#/components/responses/404NotFound'
'429':
$ref: '#/components/responses/429TooManyRequests'
'500':
$ref: '#/components/responses/500InternalServerError'
/quotes/{quoteId}/product-details:
put:
summary: Update Quote Product Details
description: 'Update the product details on a quote. The values you provide replace the current product details.
The request body must match the `productDetails` object for the quote''s product, as defined in [Product Schemas](#tag/Product-Schemas). You can''t change the quote''s `productId` or `propertyLocation` here.
'
operationId: conveyances-experience-quote-product-details-update
x-external-entitlement: external:conveyancesexperience:quote:productdetails:update
tags:
- Quotes
parameters:
- name: quoteId
in: path
required: true
description: Unique identifier for the quote
schema:
$ref: '#/components/schemas/LgsUuid'
example: 550e8400-e29b-41d4-a716-446655440000
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/QuoteProductDetails'
examples:
updateProductDetails:
$ref: '#/components/examples/UpdateQuoteProductDetailsExample'
responses:
'200':
description: Quote product details updated successfully
'400':
$ref: '#/components/responses/400BadRequest'
'401':
$ref: '#/components/responses/401Unauthorized'
'403':
$ref: '#/components/responses/403Forbidden'
'404':
$ref: '#/components/responses/404NotFound'
'429':
$ref: '#/components/responses/429TooManyRequests'
'500':
$ref: '#/components/responses/500InternalServerError'
/quotes/{quoteId}/persons:
post:
summary: Add Person to Quote
description: 'Add a person (applicant) to a quote. A quote can have up to 8 applicants.
'
operationId: conveyances-experience-quote-person-create
x-external-entitlement: external:conveyancesexperience:quote:person:create
tags:
- Quotes
parameters:
- name: quoteId
in: path
required: true
description: Unique identifier for the quote
schema:
$ref: '#/components/schemas/LgsUuid'
example: 550e8400-e29b-41d4-a716-446655440000
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Person'
examples:
addPerson:
$ref: '#/components/examples/AddQuotePersonExample'
responses:
'201':
description: Person added to quote successfully
'400':
$ref: '#/components/responses/400BadRequest'
'401':
$ref: '#/components/responses/401Unauthorized'
'403':
$ref: '#/components/responses/403Forbidden'
'404':
$ref: '#/components/responses/404NotFound'
'429':
$ref: '#/components/responses/429TooManyRequests'
'500':
$ref: '#/components/responses/500InternalServerError'
/quotes/{quoteId}/persons/{personReference}:
put:
summary: Update Person on Quote
description: 'Update a person on a quote. The values you provide replace that person''s details.
'
operationId: conveyances-experience-quote-person-update
x-external-entitlement: external:conveyancesexperience:quote:person:update
tags:
- Quotes
parameters:
- name: quoteId
in: path
required: true
description: Unique identifier for the quote
schema:
$ref: '#/components/schemas/LgsUuid'
example: 550e8400-e29b-41d4-a716-446655440000
- name: personReference
in: path
required: true
description: Unique identifier for the person on the quote
schema:
$ref: '#/components/schemas/LgsUuid'
example: bf13cb52-6676-4f3d-a27a-b6cafaf52f19
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateQuotePersonRequest'
examples:
updatePerson:
$ref: '#/components/examples/UpdateQuotePersonExample'
responses:
'200':
description: Person updated successfully
'400':
$ref: '#/components/responses/400BadRequest'
'401':
$ref: '#/components/responses/401Unauthorized'
'403':
$ref: '#/components/responses/403Forbidden'
'404':
$ref: '#/components/responses/404NotFound'
'429':
$ref: '#/components/responses/429TooManyRequests'
'500':
$ref: '#/components/responses/500InternalServerError'
delete:
summary: Remove Person from Quote
description: 'Remove a person from a quote.
'
operationId: conveyances-experience-quote-person-delete
x-external-entitlement: external:conveyancesexperience:quote:person:delete
tags:
- Quotes
parameters:
- name: quoteId
in: path
required: true
description: Unique identifier for the quote
schema:
$ref: '#/components/schemas/LgsUuid'
example: 550e8400-e29b-41d4-a716-446655440000
- name: personReference
in: path
required: true
description: Unique identifier for the person on the quote
schema:
$ref: '#/components/schemas/LgsUuid'
example: bf13cb52-6676-4f3d-a27a-b6cafaf52f19
responses:
'200':
description: Person removed from quote successfully
'400':
$ref: '#/components/responses/400BadRequest'
'401':
$ref: '#/components/responses/401Unauthorized'
'403':
$ref: '#/components/responses/403Forbidden'
'404':
$ref: '#/components/responses/404NotFound'
'429':
$ref: '#/components/responses/429TooManyRequests'
'500':
$ref: '#/components/responses/500InternalServerError'
/cases:
get:
summary: List Cases
description: 'Retrieve your cases, most recently updated first. As a conveyancer these are the cases assigned to you; as an introducer these are the cases you''ve instructed.
Filter, sort, and page the results with the OData-style query parameters below.
'
operationId: conveyances-experience-case-list
x-external-entitlement: external:conveyancesexperience:case:list
tags:
- Cases
parameters:
- name: $filter
in: query
description: 'OData $filter syntax i.e. $filter=status eq ''Completed'' <br/><br/> Supported $filter values are: ''status'', ''createdDate'', ''updatedDate'', ''productId'''
required: false
schema:
type: string
maxLength: 1000
- name: $orderby
in: query
description: 'OData $orderby syntax i.e. $orderby=updatedDate desc <br/><br/> Supported $orderby values are: ''createdDate'', ''updatedDate'', ''productName'', ''status'''
required: false
schema:
type: string
maxLength: 1000
default: updatedDate desc
- name: $top
in: query
description: The number of items to return
schema:
type: integer
format: int32
minimum: 1
maximum: 999
default: 20
- name: $skip
in: query
description: The number of items to skip
schema:
type: integer
format: int32
minimum: 0
maximum: 9999999
default: 0
- name: $count
in: query
description: Whether or not to return a count of items
schema:
type: boolean
default: false
- name: countOnly
in: query
description: Return only the count of items
schema:
type: boolean
default: false
responses:
'200':
description: List of cases retrieved successfully
content:
application/json:
schema:
$ref: '#/components/schemas/CaseListResponse'
examples:
caseList:
$ref: '#/components/examples/CaseListResponseExample'
'400':
$ref: '#/components/responses/400BadRequest'
'401':
$ref: '#/components/responses/401Unauthorized'
'403':
$ref: '#/components/responses/403Forbidden'
'404':
$ref: '#/components/responses/404NotFound'
'429':
$ref: '#/components/responses/429TooManyRequests'
'500':
$ref: '#/components/responses/500InternalServerError'
/cases/{caseId}:
get:
summary: Retrieve Case Details
description: 'Retrieve the full detail of one of your cases, including its current status, activities, and documents.
'
operationId: conveyances-experience-case-read
x-external-entitlement: external:conveyancesexperience:case:read
tags:
- Cases
parameters:
- name: caseId
in: path
required: true
description: Unique identifier for the case
schema:
$ref: '#/components/schemas/LgsUuid'
responses:
'200':
description: Case details retrieved successfully
content:
application/json:
schema:
$ref: '#/components/schemas/RetrieveCaseResponse'
examples:
retrieveCase:
$ref: '#/components/examples/RetrieveCaseResponseExample'
'400':
$ref: '#/components/responses/400BadRequest'
'401':
$ref: '#/components/responses/401Unauthorized'
'403':
$ref: '#/components/responses/403Forbidden'
'404':
$ref: '#/components/responses/404NotFound'
'429':
$ref: '#/components/responses/429TooManyRequests'
'500':
$ref: '#/components/responses/500InternalServerError'
/cases/{caseId}/accept:
post:
summary: Accept Case
description: 'Accept a case that has been instructed to you.
'
operationId: conveyances-experience-case-accept
x-external-entitlement: external:conveyancesexperience:case:accept
tags:
- Cases
parameters:
- name: caseId
in: path
required: true
description: Unique identifier for the case
schema:
$ref: '#/components/schemas/LgsUuid'
responses:
'200':
description: Case successfully accepted
'400':
$ref: '#/components/responses/400BadRequest'
'401':
$ref: '#/components/responses/401Unauthorized'
'403':
$ref: '#/components/responses/403Forbidden'
'404':
$ref: '#/components/responses/404NotFound'
'429':
$ref: '#/components/responses/429TooManyRequests'
'500':
$ref: '#/components/responses/500InternalServerError'
/cases/{caseId}/reject:
post:
summary: Reject Case
description: 'Reject a case that has been instructed to you. A reason must be provided.
'
operationId: conveyances-experience-case-reject
x-external-entitlement: external:conveyancesexperience:case:reject
tags:
- Cases
parameters:
- name: caseId
in: path
required: true
description: Unique identifier for the case
schema:
$ref: '#/components/schemas/LgsUuid'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/RejectCaseRequest'
examples:
rejectCase:
$ref: '#/components/examples/RejectCaseExample'
responses:
'200':
description: Case successfully rejected
'400':
$ref: '#/components/responses/400BadRequest'
'401':
$ref: '#/components/responses/401Unauthorized'
'403':
$ref: '#/components/responses/403Forbidden'
'404':
$ref: '#/components/responses/404NotFound'
'429':
$ref: '#/components/responses/429TooManyRequests'
'500':
$ref: '#/components/responses/500InternalServerError'
/cases/{caseId}/status:
post:
summary: Change Case Status
description: 'Update the status of a case — place on hold, cancel, or resume from hold back to in progress. A reason must be provided for the change.
'
operationId: conveyances-experience-case-status-update
x-external-entitlement: external:conveyancesexperience:case:status
# --- truncated at 32 KB (147 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/landmark-information/refs/heads/main/openapi/landmark-information-conveyancing-experience-api-openapi.yml