Skip to content
Developers
esc
  • Type an endpoint, an object or a word from a guide.

Getting started

Quick start

Credentials, a token and your first call, in ten minutes.

The API lets your own systems read and write one organisation’s data in Quarters. A website reads listings and the calendar and posts inquiries. A contract, accounting or reporting system reads reservations and their agreements. Both subscribe to webhooks instead of polling.

The base URL is https://go.quarters.live/api/v1.

1. Create credentials

In the dashboard, open Settings › Integrations and create an API credential. You get a client ID (qc_…) and a client secret (qs_…). The secret is shown once. If you lose it, create a new set.

2. Get a token

Exchange the credentials for an access token at the token endpoint. The token lasts 24 hours. Cache and re-use it, and mint a new one when a call answers 401.

Request

curl -X POST "https://go.quarters.live/api/v1/oauth2/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "client_id=qc_YOUR_CLIENT_ID" \
  -d "client_secret=qs_YOUR_CLIENT_SECRET"
const res = await fetch("https://go.quarters.live/api/v1/oauth2/token", {
  method: "POST",
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
  body: new URLSearchParams({
    "grant_type": "client_credentials",
    "client_id": "qc_YOUR_CLIENT_ID",
    "client_secret": "qs_YOUR_CLIENT_SECRET"
  })
});
const data = await res.json();
import requests

res = requests.post(
    "https://go.quarters.live/api/v1/oauth2/token",
    data={
      "grant_type": "client_credentials",
      "client_id": "qc_YOUR_CLIENT_ID",
      "client_secret": "qs_YOUR_CLIENT_SECRET",
    },
)
res.raise_for_status()
data = res.json()
$ch = curl_init("https://go.quarters.live/api/v1/oauth2/token");
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_POST => true,
  CURLOPT_HTTPHEADER => ["Content-Type: application/x-www-form-urlencoded"],
  CURLOPT_POSTFIELDS => http_build_query([
    "grant_type" => "client_credentials",
    "client_id" => "qc_YOUR_CLIENT_ID",
    "client_secret" => "qs_YOUR_CLIENT_SECRET",
  ]),
]);
$res = curl_exec($ch);
curl_close($ch);
$data = json_decode($res, true);
require "net/http"
require "json"

uri = URI("https://go.quarters.live/api/v1/oauth2/token")
req = Net::HTTP::Post.new(uri)
req.set_form_data({
  "grant_type" => "client_credentials",
  "client_id" => "qc_YOUR_CLIENT_ID",
  "client_secret" => "qs_YOUR_CLIENT_SECRET",
})
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)
package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"os"
	"strings"
)

func main() {
	token := os.Getenv("ACCESS_TOKEN")
	form := url.Values{
		"grant_type": {"client_credentials"},
		"client_id": {"qc_YOUR_CLIENT_ID"},
		"client_secret": {"qs_YOUR_CLIENT_SECRET"},
	}
	req, _ := http.NewRequest("POST", "https://go.quarters.live/api/v1/oauth2/token", strings.NewReader(form.Encode()))
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	var data map[string]any
	json.NewDecoder(res.Body).Decode(&data)
	fmt.Println(data)
}

Response · 200

{
  "token_type": "Bearer",
  "access_token": "qat_…",
  "expires_in": 86400
}

3. Make your first call

Send the token as Authorization: Bearer on every call. This lists your organisation’s published listings, sorted by nickname:

Request

curl "https://go.quarters.live/api/v1/listings" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
const res = await fetch("https://go.quarters.live/api/v1/listings", {
  headers: { Authorization: `Bearer ${token}` }
});
const { listings } = await res.json();
import requests

res = requests.get(
    "https://go.quarters.live/api/v1/listings",
    headers={"Authorization": f"Bearer {token}"},
)
res.raise_for_status()
listings = res.json()["listings"]
$ch = curl_init("https://go.quarters.live/api/v1/listings");
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => ["Authorization: Bearer $token"],
]);
$res = curl_exec($ch);
curl_close($ch);
$listings = json_decode($res, true)["listings"];
require "net/http"
require "json"

uri = URI("https://go.quarters.live/api/v1/listings")
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer #{token}"
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
listings = JSON.parse(res.body)["listings"]
package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"os"
)

func main() {
	token := os.Getenv("ACCESS_TOKEN")
	req, _ := http.NewRequest("GET", "https://go.quarters.live/api/v1/listings", nil)
	req.Header.Set("Authorization", "Bearer "+token)
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	var data map[string]any
	json.NewDecoder(res.Body).Decode(&data)
	fmt.Println(data["listings"])
}

An empty listings array means nothing is published yet. The API serves what Publish froze, never what is being edited. Publish a property in the dashboard and call again.

Where to go next