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 three paths: the fastest way to try the API (the interactive docs playground), the simplest way to run your own scripts (a personal API credential created in the app) and the standard OAuth flow you will use when you build an app for other hosts.

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 create a personal API credential or register your own OAuth client (both explained below).

Your own scripts: create a personal API credential

If you are automating your own account (a reporting script, a sync with your accounting tool, a small dashboard), you do not need the full OAuth flow at all. Create a personal API credential in the app and exchange it for a token in a single call. No consent screen, no refresh tokens to manage.

  1. In the app, open the menu and go to My account > Developer, or open app.nowistay.com/hub/user/developer directly.
  2. Click New credential.
  3. Give it a clear name (for example Reporting script) and tick only the permissions it needs.
  4. Click Create credential. The secret key is shown once: copy it now and store it somewhere safe. You will not be able to see it again.

[Screenshot to add: the Developer page with the New credential dialog open, showing the name field and the permissions checkboxes]

Your script then exchanges the credential for an access token (valid one hour) and calls the API:

curl -X POST https://api.nowistay.com/public/oauth/token \
-d grant_type=client_credentials \
-d client_id=YOUR_CLIENT_ID \
-d client_secret=YOUR_CLIENT_SECRET

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

When the token expires, request a new one the same way. There is no refresh token on this flow, and that is the point: two lines of code, nothing to babysit.

Managing your credentials

  • Last used shows when each credential last called the API. It is the easiest way to spot an old script that still runs, or a credential you can safely remove.
  • Rotate secret generates a new secret key if the current one may have leaked, or when you rotate keys periodically. The new key is shown once; the previous key keeps working for 7 days so your script can migrate, then it stops.
  • Delete removes a credential you no longer use. Anything still using it stops working immediately.

You can create up to 10 credentials, each with its own name and permissions. A credential only reads and writes the data your own account can access, and it needs the same active AI Channel Manager subscription as the rest of the API.

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.

New apps start as unverified

Anyone can register an OAuth client, so hosts need a way to tell a brand-new app from an established integration. Every newly registered app therefore starts as unverified:

  • The consent screen shows hosts a clear warning that the app has not been verified by Nowistay.
  • An unverified app can be connected to a maximum of 3 host accounts.
  • Registered clients that never complete a single connection are cleaned up automatically after 30 days.

Building something for more than 3 accounts? Write to support with your app name, website and use case. Once your app is verified, the warning disappears and the account limit is lifted.

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.
  • customers.read: List guest profiles with their contact details (email, phone).

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 Booking Sync",
"redirectUris": ["https://myapp.example.com/oauth/callback"],
"tokenEndpointAuthMethod": "none"
}'

Response (shortened):

{
  "client_id": "client_2Yw4Rk9pQp",
  "client_id_issued_at": 1771945200,
  "client_secret_expires_at": 0,
  "client_name": "My Booking Sync",
  "redirect_uris": ["https://myapp.example.com/oauth/callback"],
  "grant_types": ["authorization_code", "refresh_token"],
  "response_types": ["code"],
  "token_endpoint_auth_method": "none"
}

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://myapp.example.com/oauth/callback
&scope=properties.read%20bookings.read
&state=state_8d7f3
&code_challenge=YOUR_S256_CODE_CHALLENGE
&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://myapp.example.com/oauth/callback?code=auth_code_123&state=state_8d7f3

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 \
-d grant_type=authorization_code \
-d code=auth_code_123 \
-d client_id=client_2Yw4Rk9pQp \
-d redirect_uri=https://myapp.example.com/oauth/callback \
-d code_verifier=YOUR_CODE_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",
  "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"
    }
  ],
  "pagination": { "limit": 20, "offset": 0, "total": 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 \
-d grant_type=refresh_token \
-d refresh_token=nis_refresh_token_example \
-d client_id=client_2Yw4Rk9pQp

Endpoint examples

List bookings for a property in a date range

curl "https://api.nowistay.com/public/v1/bookings?propertyId=101&fromDate=2026-08-01&toDate=2026-08-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"

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 '{
"departure": "2026-08-25",
"adults": 2,
"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.

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" }'

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-08-25T11:30:00Z",
"timezone": "Europe/Paris",
"assignedTeamMemberId": 301
}'

Read the activity feed of a property

curl https://api.nowistay.com/public/v1/properties/101/activity \
-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.