Quickstart
The shortest path from an approved client to an authenticated call. Everything here works against sandbox credentials, so you can complete it before Haven has reviewed you for production.
The resource endpoints and the authorization server are in active development. This page describes the contract they implement. Until they ship, treat it as the specification you are building against rather than a live tutorial.
What you need
Your client_id, which looks like hvci_ followed by an opaque string, and your client_secret, which looks like hvcs_.... If your client is public (a native app, a CLI, an MCP server) you have no secret and authenticate with PKCE alone.
One registered redirect URI. For a first pass, http://127.0.0.1:8976/callback is fine; loopback URIs may use any port at request time, so you do not have to register the port your server happens to bind.
1. Send the host to authorize
Generate a PKCE verifier and challenge. The verifier is 43 to 128 characters from the unreserved set; the challenge is its SHA-256 digest, base64url encoded without padding.
VERIFIER=$(openssl rand -base64 60 | tr -d '=+/' | cut -c1-64)
CHALLENGE=$(printf '%s' "$VERIFIER" | openssl dgst -binary -sha256 | openssl base64 | tr '+/' '-_' | tr -d '=')
Then build the authorization URL and open it in the host's browser.
https://www.bookwithhaven.com/oauth/authorize
?response_type=code
&client_id=hvci_your_client
&redirect_uri=http%3A%2F%2F127.0.0.1%3A8976%2Fcallback
&scope=account%3Aread%20listings%3Aread%20calendar%3Aread%20calendar%3Awrite
&state=<random, and check it on the way back>
&code_challenge=$CHALLENGE
&code_challenge_method=S256
Scopes are space separated. S256 is the only accepted challenge method; plain is rejected. state is required.
The host sees what your application is, which of their accounts they are connecting, and a plain-language line for every scope you asked for. If they approve, Haven redirects to your redirect_uri with code, state and iss.
2. Exchange the code for tokens
Within sixty seconds, and only once.
curl -X POST https://www.bookwithhaven.com/api/public/oauth/token \
-u "$CLIENT_ID:$CLIENT_SECRET" \
-d grant_type=authorization_code \
-d code="$CODE" \
-d redirect_uri="http://127.0.0.1:8976/callback" \
-d code_verifier="$VERIFIER"
{
"access_token": "hvat_...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "hvrt_...",
"scope": "account:read listings:read calendar:read calendar:write"
}
Read the scope field rather than assuming you received what you asked for. Haven returns it on every token response, including when it is unchanged, precisely so a narrowing is visible to you at the moment it happens.
3. Call the API
curl https://www.bookwithhaven.com/api/public/v1/me \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "User-Agent: YourProduct/1.2.0 (you@example.com)"
{
"success": true,
"value": {
"account": {
"code": "b41c9e07",
"displayName": "Cascade Rentals",
"timezone": "America/Los_Angeles",
"currencyCode": "USD"
},
"application": { "clientId": "hvci_your_client", "name": "Your Product" },
"scopes": [
"account:read",
"listings:read",
"calendar:read",
"calendar:write"
],
"context": { "kind": "own-default", "role": "OWNER", "canWrite": true },
"connectedAt": "2026-08-31T14:02:11.000Z"
},
"error": null
}
/me is the call to make first in any integration. It tells you whose account you are holding, what you may do with it, and whether a write will succeed before you compose one.
The User-Agent is not optional. It must name your product and carry a contact address, so that when your integration is responsible for a traffic spike Haven can reach you rather than guess.
4. Make a write
Writes are a single endpoint. You name an operation and send its input.
curl -X POST https://www.bookwithhaven.com/api/public/v1/operations/block_dates \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-H "User-Agent: YourProduct/1.2.0 (you@example.com)" \
-d '{"propertyCode":"a1b2c3d4","startDate":"2026-09-14","endDate":"2026-09-17","notes":"Owner stay"}'
The Idempotency-Key is required on every write. Retrying with the same key replays the stored result instead of blocking the dates twice. See Idempotency.
What to read next
The authorization flow covers refresh, rotation and revocation, all of which you need before you ship.
Errors is worth reading in full once. Haven's error bodies carry more than a message, and handling them properly removes most of the reasons you would otherwise write to support.