{"openapi":"3.1.0","info":{"title":"Best Rated Company application API","version":"1","summary":"Apply for a business to be listed.","description":"Ask for a business to be listed in Best Rated Company, a free directory that checks every listing by phone and email. This is the website's own application form with JSON: the application is saved and emailed to a person in the same way, and goes through the same steps. **Every application is read by a person before anything is listed**, and a listing goes live only when the business has passed the checks for its country. Nobody can pay to be listed, verified or ranked.\n\nNo sign-in or key is needed. Limits protect the service (see the `429` and `503` answers), and a request that is repeated with the same `Idempotency-Key` returns the first answer instead of making a second application.\n\nStart with `POST /lookups` to read the business's own website, let the business check and correct what it found, then `POST /applications`, then follow `GET /applications/{id}`.\n\nDocumentation for people: https://www.bestratedcompany.co.uk/developers/","termsOfService":"https://www.bestratedcompany.co.uk/terms/","contact":{"name":"Best Rated Company","url":"https://www.bestratedcompany.co.uk/contact/"}},"servers":[{"url":"https://www.bestratedcompany.co.uk/api/v1","description":"Best Rated Company"}],"tags":[{"name":"Applications","description":"Apply for a listing, and follow it."},{"name":"Website look-up","description":"Read a business's own website for its details."},{"name":"Service","description":"About the API."}],"paths":{"/":{"get":{"operationId":"getIndex","tags":["Service"],"summary":"What the API is, and where everything is","responses":{"200":{"description":"A short description with links.","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/health":{"get":{"operationId":"getHealth","tags":["Service"],"summary":"Is the API up, and is it taking applications","responses":{"200":{"description":"Up.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Health"}}}},"503":{"description":"Down.","headers":{"Retry-After":{"description":"Seconds to wait before trying again.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Health"}}}}}}},"/lookups":{"post":{"operationId":"createLookup","tags":["Website look-up"],"summary":"Read a business's own website","description":"Reads the website the business gave and suggests its name, phone number, email address, trade and town. **These are suggestions to check with the business, not facts**: correct anything that is wrong before applying. Nothing is listed or emailed by a look-up. It can take up to a minute, so allow 90 seconds. The same website looked up again within a day is answered from the stored result. The `lookup_ref` it returns is valid for 24 hours and goes in the application. The look-up has its own limits (6 an hour and 15 a day per connection).","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LookupRequest"},"example":{"url":"www.taylorplumbing.example","country":"GB"}}}},"responses":{"200":{"description":"The website was read.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LookupResult"}}}},"400":{"description":"The body is not valid JSON.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The business is already listed (code `listed`). The problem carries `listing_url` and `update_url`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"415":{"description":"The body is not JSON.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The address cannot be used (`website_invalid`), or the site could not be read (`website_unreadable`: apply without the look-up, with `lookup_failed`).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Too many look-ups (`rate_limited`).","headers":{"Retry-After":{"description":"Seconds to wait before trying again.","schema":{"type":"integer"}}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"503":{"description":"Look-ups are not available (`lookup_unavailable`, `busy`), or the site is not taking listings (`signups_closed`). The problem says what to send as `lookup_failed`.","headers":{"Retry-After":{"description":"Seconds to wait before trying again.","schema":{"type":"integer"}}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/applications":{"post":{"operationId":"createApplication","tags":["Applications"],"summary":"Apply for a listing","description":"Makes an application, exactly as the website form does. The answer is `201` with an `id`: the application has been received and sent to a person. It has **not** been listed.\n\nThe rules are the website form's: the business needs its **own website** (not a social page, marketplace shop or directory listing); the phone number has to be a working business number for the country, and **one the website shows** when the look-up read the site (to have us ring or text a different number for the checks, use `check_phone`); the email address can be any the business reads; `consent` has to be true; and an agency, assistant or AI agent applying for a business must say so and confirm the business knows (`submitter: agency`, `agency_told: true`). Businesses outside the country, and kinds of business the directory does not list, are turned away.\n\nSend an `Idempotency-Key` so a retry cannot make a second application.","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApplicationRequest"},"example":{"country":"GB","name":"Sam Taylor","business":"Taylor & Sons Plumbing","email":"hello@taylorplumbing.example","phone":"01632 960123","trade":"Plumbers","town":"Leeds","website":"https://www.taylorplumbing.example","message":"Boiler servicing and repairs, bathrooms and emergency call-outs.","consent":true,"submitter":"agency","agency_name":"ExampleAssistant, run by Example Ltd","agency_told":true,"lookup_ref":"a1b2c3d4e5f60718293a4b5c"}}}},"responses":{"201":{"description":"Received. A person reads it next.","headers":{"Location":{"description":"Where to follow the application.","schema":{"type":"string","format":"uri"}},"Idempotency-Replayed":{"description":"true when this is the first answer, returned again for a repeated Idempotency-Key.","schema":{"type":"string"}},"RateLimit-Limit":{"schema":{"type":"integer"},"description":"Applications allowed an hour from this connection."},"RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Applications left in the window."},"RateLimit-Reset":{"schema":{"type":"integer"},"description":"Seconds until the window has room again."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApplicationCreated"}}}},"400":{"description":"The body is not valid JSON, or the Idempotency-Key is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Not accepted (`not_accepted`). The answer is the same whatever the reason, as on the website form: a blocked person, email address or website, or probably not a business of this country.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The business is already listed on that trade and town page (`listed`). The problem carries `listing_url` and `update_url`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"413":{"description":"The body is over 32 KB.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"415":{"description":"The body is not JSON.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"Something in the application has to change. `errors` lists each field with a stable `code`; see the codes in the documentation. Also `idempotency_key_reused` and `not_listed`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Too many applications from this connection (`rate_limited`).","headers":{"Retry-After":{"description":"Seconds to wait before trying again.","schema":{"type":"integer"}}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"503":{"description":"Not taking listings (`signups_closed`), busy (`busy`), switched off (`api_closed`), or we could not take it (`send_failed`). Retry later.","headers":{"Retry-After":{"description":"Seconds to wait before trying again.","schema":{"type":"integer"}}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/applications/{id}":{"get":{"operationId":"getApplication","tags":["Applications"],"summary":"Where an application has got to","description":"The `id` is the secret that only the sender of the application has. The answer holds no personal details: no email address, phone number or name. Applications are kept for 90 days, then deleted.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","pattern":"^[0-9a-f]{32}$"},"description":"The `id` from the 201 answer."}],"responses":{"200":{"description":"The application.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApplicationStatus"}}}},"404":{"description":"No application with that id (`not_found`): wrong, deleted after 90 days, or declined.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Too many requests (`rate_limited`).","headers":{"Retry-After":{"description":"Seconds to wait before trying again.","schema":{"type":"integer"}}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}}},"components":{"parameters":{"IdempotencyKey":{"name":"Idempotency-Key","in":"header","required":false,"description":"A unique key you make for this application (a UUID is fine; 16 to 128 characters). Repeat the request with the same key and the same body, and you get the first answer back, with `Idempotency-Replayed: true`, instead of a second application. The same key with a different body is refused (`idempotency_key_reused`). Kept for 24 hours.","schema":{"type":"string","minLength":16,"maxLength":128,"pattern":"^[A-Za-z0-9._:~-]+$"}}},"schemas":{"Problem":{"type":"object","description":"An error, as RFC 9457 problem details. Read `code`; it does not change. `detail` is for a person and may change.","required":["type","title","status","code"],"properties":{"type":{"type":"string","description":"A link to the explanation of this kind of problem.","format":"uri"},"title":{"type":"string","description":"A short name for the problem."},"status":{"type":"integer"},"code":{"type":"string","description":"A stable code for programs."},"detail":{"type":"string","description":"What happened and what to do, in words."},"errors":{"type":"array","items":{"$ref":"#/components/schemas/FieldError"}}},"additionalProperties":true},"FieldError":{"type":"object","required":["field","code","detail"],"properties":{"field":{"type":"string","description":"The field in the request, or empty when it is about the request as a whole."},"code":{"type":"string","description":"A stable code, for example `required`, `too_long`, `email`, `phone_format`, `phone_site`, `website_own`, `lookup_needed`."},"detail":{"type":"string","description":"In words."}}},"Health":{"type":"object","properties":{"status":{"type":"string","enum":["ok","closed","down"],"description":"`ok`, `closed` (switched off or not set up) or `down`."},"applications":{"type":"object","description":"Per country: `open` or `closed`.","additionalProperties":{"type":"string","enum":["open","closed"]}},"lookups":{"type":"string","enum":["available","unavailable"]},"database":{"type":"string"},"time":{"type":"string","format":"date-time"}}},"LookupRequest":{"type":"object","required":["url"],"properties":{"url":{"type":"string","description":"The business's own website, for example `www.example.co.uk`. Not a social page, marketplace shop or directory listing.","maxLength":300},"country":{"type":"string","description":"The country the business is in. Optional here: this site takes only GB and assumes it.","enum":["GB"]}}},"LookupResult":{"type":"object","properties":{"lookup_ref":{"type":"string","description":"Send this in the application as `lookup_ref`."},"expires_at":{"type":"string","format":"date-time"},"cached":{"type":"boolean","description":"True when answered from a look-up of the same website in the last day."},"website":{"type":"string","description":"The website's address after its own redirects."},"found":{"type":"object","description":"Suggestions. Check them with the business.","properties":{"business":{"type":"string"},"phone":{"type":"string"},"email":{"type":"string"},"description":{"type":"string"},"trade":{"type":"string","description":"A trade the directory uses, or a new one (`trade_is_new`)."},"trade_is_new":{"type":"boolean"},"trade_alternatives":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"is_new":{"type":"boolean"}}}},"town":{"type":"string"}}},"site_contacts":{"type":"object","description":"Every phone number and email address the website shows. The phone in the application has to be one of these.","properties":{"phones":{"type":"array","items":{"type":"string"}},"emails":{"type":"array","items":{"type":"string"}}}},"next":{"type":"string"}}},"ApplicationRequest":{"type":"object","required":["name","business","email","phone","trade","website","consent","submitter"],"properties":{"country":{"type":"string","description":"The country the business is in. Optional here: this site takes only GB and assumes it.","enum":["GB"]},"name":{"type":"string","description":"The contact person at the business (or who applies for it).","maxLength":120},"business":{"type":"string","description":"The business's name.","maxLength":150},"email":{"type":"string","description":"An email address the business reads. We email it a confirmation link, and the business has to approve its listing.","format":"email","maxLength":190},"phone":{"type":"string","description":"The business's phone number, an ordinary number for the country (not premium rate, not abroad). When the look-up read the website, it has to be one the website shows.","maxLength":40},"check_phone":{"type":"string","description":"Optional. A number the business answers, for our call or text only. Never shown. Used where there is a phone check.","maxLength":40},"phone_show":{"type":"boolean","default":false,"description":"Show the phone number on the listing. A number that the website shows is always shown."},"trade":{"type":"string","description":"What the business does, for example `Plumbers`. Use the look-up's suggestion where it fits.","maxLength":100},"town":{"type":"string","description":"The town or city. Leave out when `online_only` is true.","maxLength":100},"online_only":{"type":"boolean","default":false,"description":"The business sells only online and has no premises customers visit. It must still be in the country and have its own website."},"website":{"type":"string","description":"The business's own website.","maxLength":300},"message":{"type":"string","description":"What the business does, in a few sentences. Becomes its description once checked.","maxLength":2000},"consent":{"type":"boolean","description":"Must be true: the business has agreed that we may email the address given, and ring or text the phone number for the checks where there is a phone check."},"submitter":{"type":"string","enum":["owner","staff","agency"],"description":"`owner` runs the business, `staff` works there, `agency` is an agency, assistant or AI agent applying for it."},"agency_name":{"type":"string","description":"When `submitter` is `agency`: who is applying, for example the assistant's name and who runs it.","maxLength":120},"agency_told":{"type":"boolean","description":"Required true when `submitter` is `agency`: the business knows about this application, and knows we will email it and ring it."},"lookup_ref":{"type":"string","description":"From `POST /lookups`. Required when you give a website, unless the look-up could not help (then use `lookup_failed`)."},"lookup_failed":{"type":"string","enum":["unreadable","error","busy","limit","off","listed"],"description":"Why there is no `lookup_ref`. We check it against our own record of look-ups."},"timezone":{"type":"string","description":"Optional. The IANA time zone of the business, for example `Europe/London`. Helps us tell a local business from one abroad.","maxLength":60}}},"ApplicationCreated":{"type":"object","properties":{"id":{"type":"string","description":"The application's id, and the secret for following it. Keep it."},"status":{"type":"string","enum":["received"]},"summary":{"type":"string"},"country":{"type":"string"},"checks":{"type":"array","items":{"type":"string","enum":["lookup","phone","email"]},"description":"The checks a listing in this country needs."},"what_happens_next":{"type":"array","items":{"type":"string"}},"delete_after":{"type":"string","format":"date-time"},"application":{"type":"object","description":"What was received. No contact details.","properties":{"business":{"type":"string"},"trade":{"type":"string"},"town":{"type":"string"},"website":{"type":"string"}}},"links":{"type":"object","properties":{"self":{"type":"string","format":"uri"},"documentation":{"type":"string","format":"uri"}}}}},"ApplicationStatus":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["received","checking","live","removed","closed"],"description":"`received`: waiting for a person. `checking`: added to the directory, the checks are under way. `live`: listed. `removed`: the business asked for its listing to be removed. `closed`: no longer open."},"summary":{"type":"string"},"next_step":{"type":"string","description":"What has to happen next, and who has to do it."},"checks":{"type":"object","description":"Once added: each check this country uses, as `not_started`, `waiting_for_business`, `in_progress`, `passed`, `needs_attention` or `none_on_file`.","additionalProperties":{"type":"string"}},"received_at":{"type":"string","format":"date-time"},"added_at":{"type":["string","null"],"format":"date-time"},"delete_after":{"type":"string","format":"date-time"},"application":{"type":"object","properties":{"business":{"type":"string"},"trade":{"type":"string"},"town":{"type":"string"},"website":{"type":"string"}}},"links":{"type":"object","properties":{"self":{"type":"string"},"listing":{"type":"string","description":"The listing, once live."},"documentation":{"type":"string"}}}}}}}}