# VisBook developer guide

visbook.com offers a small, read-only API for its published content, so agents and developers can use the site without scraping HTML. It covers pages, VisBook features and add-ons, customer stories, news, search and public contact details.

This API covers website content only. It is not an API for the VisBook PMS itself.

## Quick start

```sh
curl -s https://visbook.com/api/v1/features
curl -s 'https://visbook.com/api/v1/search?q=housekeeping'
curl -s -H 'Accept: text/markdown' https://visbook.com/about-us/
```

## Base URL and format

- Base URL: https://visbook.com/api/v1/
- Responses are JSON (`application/json`). Errors are `application/problem+json`.
- OpenAPI 3.1: https://visbook.com/openapi.json (YAML: https://visbook.com/api/openapi.yaml)
- API catalog (RFC 9727): https://visbook.com/.well-known/api-catalog

## Authentication

None. Every endpoint is public and read-only, and there are no API keys, OAuth scopes or accounts. See https://visbook.com/auth.md.

## Endpoints

| Method | Path | operationId | What it returns |
| --- | --- | --- | --- |
| GET | `/api/v1/` | `getApiIndex` | Lists the endpoints, limits and documentation links |
| GET | `/api/v1/pages` | `listPages` | Published pages, with paging and a language filter |
| GET | `/api/v1/pages/{id}` | `getPage` | One page with its summary and, when available, its Markdown content |
| GET | `/api/v1/features` | `listFeatures` | VisBook modules and add-ons |
| GET | `/api/v1/features/{id}` | `getFeature` | One module or add-on |
| GET | `/api/v1/customer-stories` | `listCustomerStories` | Published customer stories |
| GET | `/api/v1/customer-stories/{id}` | `getCustomerStory` | One customer story |
| GET | `/api/v1/news` | `listNewsArticles` | News articles, newest first |
| GET | `/api/v1/news/{id}` | `getNewsArticle` | One news article |
| GET | `/api/v1/search?q=` | `searchContent` | Full-text search across pages, features, customer stories and news |
| GET | `/api/v1/contact` | `getContactInformation` | Public sales, support and office contact details |
| GET/POST | `/ask` | `askSite` | NLWeb-style natural-language search that returns schema.org results |

## Parameters

- `lang`: language code, one of `en`, `no`, `sv`, `dk`. Default `en`.
- `page`: page number, from 1. Default 1.
- `per_page`: items per page, 1–50 (search: 1–20). Default 20 (search: 10).
- `q`: search words, 2–100 characters. Required for search.

## Paging

List responses contain `data`, `meta` (`page`, `per_page`, `total`, `total_pages`, `language`) and `links` (`self`, `first`, `last`, and `prev` or `next` when they exist). The same links are sent in the `Link` header.

## Markdown pages

Every public HTML page can be read as Markdown:

- send `Accept: text/markdown` to the normal URL (the response has `Vary: Accept`), or
- add `.md` to the path, for example https://visbook.com/our-features.md, or https://visbook.com/index.md for the home page.

Markdown responses start with front matter (title, description, canonical URL, language, last update). HTML pages advertise their Markdown version with `<link rel="alternate" type="text/markdown">`.

## Rate limits

The API allows 600 requests per 60 seconds, shared by all clients. Every API response carries `RateLimit-Policy` and `RateLimit` (IETF structured fields) plus `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`. When the quota is used up you get `429` with `Retry-After`.

## Errors

Errors use RFC 9457 problem details (`application/problem+json`):

```json
{
  "type": "https://visbook.com/developers.md#error-not-found",
  "title": "Not found",
  "status": 404,
  "detail": "There is no published feature with id 123.",
  "instance": "https://visbook.com/api/v1/features/123",
  "code": "not_found",
  "resolution": "List the available items with GET /api/v1/features and use an id from that list.",
  "documentation_url": "https://visbook.com/developers.md#errors"
}
```

| Status | code | When |
| --- | --- | --- |
| 400 | `invalid_parameter` | A query parameter is missing or out of range. `invalid_params` lists each problem. |
| 404 | `not_found` | The item does not exist or is not published. |
| 404 | `route_not_found` | There is no endpoint at that path. |
| 405 | `method_not_allowed` | The method is not GET, HEAD or OPTIONS (POST is allowed on /ask). |
| 429 | `rate_limit_exceeded` | The shared quota is used up. Wait for `Retry-After`. |
| 500 | `internal_error` | Something failed on the server. Try again later. |

Requests for pages that do not exist return `404` with a Markdown body when you ask for `text/markdown`, and problem details when you ask for `application/json`.

## Versioning and deprecation

The major version is part of the path (`/api/v1/`). Changes inside v1 only add fields or endpoints. A breaking change gets a new path (`/api/v2/`). The old version then keeps working for a transition period, announced with `Deprecation` and `Sunset` headers (RFC 9745 and RFC 8594). Every response carries `API-Version` with the exact version (now 1.0.0).

## Caching

Responses carry an `ETag`. Send `If-None-Match` to get `304 Not Modified` when nothing has changed. Content can be up to one hour old.

## Contact

Questions about VisBook: https://visbook.com/contact/. Customer support: https://jwt.visbook.com/zendesk/login2 or support@visbook.com.
