Using the Nowistay public REST API

All help ressources
>
Using the Nowistay public REST API

The Nowistay public REST API lets your own tools, scripts and partners read and update data from your Nowistay account in a secure way. You can list properties, fetch bookings, update direct reservations, create cleaning or check-in missions, manage custom booking fields and pull a feed of activity events. Everything is documented, browsable and testable from a single page at /public/docs.

This guide walks you through two paths: the fastest way to try the API (the interactive docs playground) and the standard OAuth flow you will use when you build your own integration.

What you can do with the API

  • Properties: list the properties on your account, with address, capacity, check-in and check-out times.
  • Bookings: list and filter reservations by property, channel, status and dates. Read a full booking detail. Update direct bookings (dates, guest info, amounts, custom fields).
  • Booking parameters: create your own custom fields on bookings (for example external_status) and set their values per reservation.
  • Missions: list cleaning, check-in, check-out and other on-site missions. Create or update a mission, assign it to a team member.
  • Team members: list your team, their roles, contact info and which properties they cover.
  • Activity: read a chronological feed of events on a property (booking updates, automations, smart lock events).

Before you start

  • You need an active AI Channel Manager subscription on the properties you want to expose. The API only returns properties where this entitlement is active.
  • You sign in as a host or property manager. The API never exposes properties you do not own.
  • The base URL is https://api.nowistay.com
  • All endpoints under /public/v1/* require an OAuth2 access token, sent as Authorization: Bearer ....

The fastest way: try it from the docs playground

Open https://api.nowistay.com/public/docs in your browser. The page is a full Swagger UI of the API, with a built-in OAuth playground that auto-registers a client for you. No coding needed to test calls.

  1. Hard-refresh the page (Cmd+Shift+R on Mac, Ctrl+F5 on Windows).
  2. Wait for the small banner at the top to say OAuth playground ready.
  3. Click the green Authorize button (top right).
  4. In the dialog, in the OAuth2 section, click Authorize.
  5. You are redirected to the Nowistay login and consent page.
  6. Log in as a host or property manager with the AI Channel Manager subscription.
  7. Review the scopes the playground is asking for and approve them.
  8. You land back on /public/docs, already authenticated.
  9. Open GET /public/v1/properties, click Try it out, then Execute.
  10. You should see your properties in the response.

[Screenshot to add: the /public/docs page with the green "OAuth playground ready" banner at the top and the Authorize button on the right]

From there you can try every endpoint with one click, see the exact JSON Nowistay returns and copy the cURL command for any call. This is the recommended way to explore the API before writing code.

Important. The playground client lives only in your browser. It is fine for testing, but for a real integration you should register your own OAuth client (see below).

OAuth, in plain terms

The API uses standard OAuth 2.1 with the authorization code flow and PKCE. In one sentence: the user opens a Nowistay page, says yes, you receive a short code, you exchange it for an access token, and you call the API with that token. Tokens expire and can be refreshed without bothering the user again.

The three OAuth endpoints you will use:

  • Register your app (one time): /public/oauth/register — POST
  • Send the user to give consent: /public/oauth/authorize — GET (browser redirect)
  • Exchange the code for tokens: /public/oauth/token — POST

You can also fetch the OAuth metadata at /.well-known/oauth-authorization-server/public-api, which lists every endpoint and supported feature.

Available scopes

Ask only for the scopes your app actually needs. The fewer scopes you request, the faster the consent screen reads.

  • properties.read: List properties and their basic info.
  • bookings.read: List bookings and read a booking detail (no guest contact info).
  • bookings.sensitive.read: Adds guest email, phone, address and smart-lock code to the booking detail.
  • bookings.write: Update direct bookings (dates, amounts, guest info).
  • booking_parameters.read: List your custom booking fields.
  • booking_parameters.write: Create custom booking fields and set values on bookings.
  • missions.read: List missions on your properties.
  • missions.write: Create or update missions, assign team members.
  • activity.read: Read the activity feed for a property.
  • team_members.read: List team members and their property assignments.
  • webhooks.read: List your webhook subscriptions and read their config.
  • webhooks.write: Create, update, pause and delete webhook subscriptions.

Step by step: build your own integration

Step 1. Register your OAuth client

Call POST /public/oauth/register once. Save the client_id (and client_secret if you set token_endpoint_auth_method to something other than none).

curl -X POST https://api.nowistay.com/public/oauth/register \
  -H "Content-Type: application/json" \
  -d '{
    "clientName": "My PMS Integration",
    "redirectUris": ["https://my-app.example.com/oauth/callback"],
    "grantTypes": ["authorization_code", "refresh_token"],
    "responseTypes": ["code"],
    "tokenEndpointAuthMethod": "client_secret_post",
    "scope": "properties.read bookings.read missions.read"
  }'

Response (shortened):

{
  "client_id": "client_2Yw4Rk9pQp",
  "client_secret": "client_secret_example",
  "redirect_uris": ["https://my-app.example.com/oauth/callback"],
  "scope": "properties.read bookings.read missions.read"
}

Tip: if you are building a single-page app or a CLI without a backend, use "tokenEndpointAuthMethod": "none" and rely on PKCE only (no client secret). The Nowistay docs playground does exactly that.

Step 2. Send the user to the authorize URL

Generate a PKCE pair (code verifier and S256 code challenge) and a random state value. Then redirect the user to:

https://api.nowistay.com/public/oauth/authorize
  ?response_type=code
  &client_id=client_2Yw4Rk9pQp
  &redirect_uri=https://my-app.example.com/oauth/callback
  &scope=properties.read%20bookings.read%20missions.read
  &state=RANDOM_STATE
  &code_challenge=BASE64URL_S256_HASH
  &code_challenge_method=S256

The user lands on the Nowistay consent page, signs in if needed, sees the scopes you requested, and approves or denies. On approval, Nowistay redirects back to your redirect_uri with a one-time code and the same state you sent.

https://my-app.example.com/oauth/callback?code=auth_code_123&state=RANDOM_STATE

Always check that state matches what you sent. If it does not, abort.

Step 3. Exchange the code for tokens

curl -X POST https://api.nowistay.com/public/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code" \
  -d "code=auth_code_123" \
  -d "redirect_uri=https://my-app.example.com/oauth/callback" \
  -d "client_id=client_2Yw4Rk9pQp" \
  -d "client_secret=client_secret_example" \
  -d "code_verifier=ORIGINAL_PKCE_VERIFIER"

Response:

{
  "access_token": "nis_access_token_example",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "nis_refresh_token_example",
  "scope": "properties.read bookings.read missions.read",
  "resource": "https://api.nowistay.com/public/v1"
}

Store the access_token and the refresh_token securely on your side (server side, encrypted at rest). The access token is valid for expires_in seconds (one hour by default).

Step 4. Call the API

Send the access token in the Authorization header.

curl https://api.nowistay.com/public/v1/properties \
  -H "Authorization: Bearer nis_access_token_example"

Sample response:

{
  "data": [
    {
      "id": 101,
      "name": "Lilas Apartment",
      "propertyType": "apartment",
      "capacity": 4,
      "checkInTime": "16:00:00",
      "checkOutTime": "11:00:00",
      "address": {
        "city": "Paris",
        "country": "France",
        "countryCode": "FR",
        "timezone": "Europe/Paris"
      }
    }
  ],
  "pagination": { "page": 1, "limit": 50, "totalItems": 1, "totalPages": 1 }
}

Step 5. Refresh the token when it expires

When the API returns 401 token_expired, call the token endpoint again with the refresh token. You do not need to send the user back to the consent page.

curl -X POST https://api.nowistay.com/public/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=refresh_token" \
  -d "refresh_token=nis_refresh_token_example" \
  -d "client_id=client_2Yw4Rk9pQp" \
  -d "client_secret=client_secret_example"

Endpoint examples

List bookings for a property in a date range

curl "https://api.nowistay.com/public/v1/bookings?propertyId=101&fromDate=2026-07-01&toDate=2026-07-31&status=confirmed" \
  -H "Authorization: Bearer nis_access_token_example"

Supported filters: propertyId, status, channel, fromDate, toDate. Pagination with limit (max 100) and offset.

Get a booking detail with guest contact info

Requires the extra bookings.sensitive.read scope. Without it, email, phone and the smart-lock code are omitted.

curl https://api.nowistay.com/public/v1/bookings/9001 \
  -H "Authorization: Bearer nis_access_token_example"

curl https://api.nowistay.com/public/v1/bookings/9001 \
 -H "Authorization: Bearer nis_access_token_example"

Update a direct booking

Only direct bookings (channel direct) you created in Nowistay can be edited. Reservations from Airbnb, Booking.com, VRBO and Expedia are read-only here, because the OTA owns them.

curl -X PATCH https://api.nowistay.com/public/v1/bookings/9001 \
  -H "Authorization: Bearer nis_access_token_example" \
  -H "Content-Type: application/json" \
  -d '{
    "arrival": "2026-07-14",
    "departure": "2026-07-18",
    "adults": 2,
    "children": 1,
    "amount": "620.00",
    "currency": "EUR",
    "notes": "Guest requested a baby cot.",
    "silent": true
  }'

Set "silent": false if you want Nowistay to send the usual notifications (guest messages, calendar push) on the update. Default is silent.

Add a custom field to your bookings

Custom booking parameters are useful when you want to mirror data from your own system on each Nowistay reservation.

# Create the field once
curl -X POST https://api.nowistay.com/public/v1/booking-parameters \
  -H "Authorization: Bearer nis_access_token_example" \
  -H "Content-Type: application/json" \
  -d '{"key": "external_status", "name": "External status"}'

# Set its value on a booking
curl -X PATCH https://api.nowistay.com/public/v1/bookings/9001 \
  -H "Authorization: Bearer nis_access_token_example" \
  -H "Content-Type: application/json" \
  -d '{"customParameters": {"external_status": "ready"}}'

Send null as the value to clear a custom field on a booking.

Create a cleaning mission and assign a team member

curl -X POST https://api.nowistay.com/public/v1/missions \
  -H "Authorization: Bearer nis_access_token_example" \
  -H "Content-Type: application/json" \
  -d '{
    "propertyId": 101,
    "bookingId": 9001,
    "missionType": "cleaning",
    "title": "Checkout cleaning",
    "scheduledAt": "2026-07-18T11:30:00Z",
    "timezone": "Europe/Paris",
    "assignedTeamMemberId": 301
  }'

Read the activity feed of a property

curl https://api.nowistay.com/public/v1/properties/101/activity?limit=20 \
  -H "Authorization: Bearer nis_access_token_example"

Events are grouped into three categories: booking, mission and automation (guest messages, smart-lock events).

Webhooks (real-time events)

If you do not want to poll the API to detect changes, you can subscribe to webhooks. Nowistay will then call a URL you provide each time a booking is created or updated on the property, and send the same booking data that GET /public/v1/bookings/{id} returns.

Two events are supported today:

  • booking.created: a new reservation has been recorded on the property.
  • booking.updated: an existing reservation has changed (dates, status, guest info, smart-lock code, etc.).

Each webhook is tied to a single property and you can register up to three per property. Deliveries are signed (HMAC-SHA256) so you can verify they really come from Nowistay, retried with exponential backoff on failure, and the endpoint is auto-disabled if it keeps failing for more than 72 hours. Webhook payloads do not contain sensitive guest fields (email, phone, address, smart-lock code). When you need those, call the API with the bookings.sensitive.read scope.

Full setup and signature verification details are in the dedicated article: Public API: receive real-time booking webhooks.

Rate limits

  • Read endpoints: 120 requests per minute per client and per route.
  • Write endpoints (POST, PATCH): 30 requests per minute per client and per route.
  • OAuth endpoints: 20 requests per minute per IP or client.

When you hit the limit, the API returns 429 Rate limit exceeded. Back off and retry after a few seconds.

Error format

Every error follows the same shape, with a stable code, a human message and a requestId you can include in support requests.

{
  "error": {
    "code": "validation_error",
    "message": "Parameter key must be lowercase snake_case, start with a letter, and be at most 40 characters",
    "requestId": "req_01HYZV5R8G3W9Y2M7K4P6Q1N2A"
  }
}
  • 400: Bad request (malformed body, missing field).
  • 401: Missing or invalid bearer token.
  • 403: Token is valid but missing a required scope, or you do not have the AI Channel Manager entitlement.
  • 404: Resource not found, or you do not have access to it.
  • 409: Conflict (for example, parameter key already exists).
  • 422: Validation failed.
  • 429: Rate limit hit.

Good practices

  • Ask for the smallest scope set. Add new scopes later as your integration grows.
  • Store tokens server side. Never ship a long-lived token to a public client or commit it to a repo.
  • Handle 401 by refreshing. When refresh also fails, send the user back through the authorize flow.
  • Use the silent flag on writes. Set to true when you are syncing data in bulk and do not want to trigger guest notifications.
  • Keep the requestId in your logs. It makes support requests much faster to resolve.

Where to go next

  • Open the live docs and play with every endpoint: api.nowistay.com/public/docs.
  • Read the full schema and download an OpenAPI file at /public/openapi.json.
  • Need a scope or an endpoint that is not listed yet? Write to support and tell us about your use case.

Ready to Put Your Rental on Autopilot?

Join 300+ property managers who save hours every week with AI-powered guest communication.