Aggiornato il
L’API REST pubblica di Nowistay collega i tuoi script e le integrazioni dei partner al tuo account. Leggi e aggiorna le impostazioni degli alloggi, i calendari, le prenotazioni e le missioni; gestisci le schede ospite, le conversazioni, la conoscenza privata e le guide di benvenuto; richiedi pagamenti per le prenotazioni e rimborsi per le cancellazioni; e consulta upsell, acquisti e report del portafoglio. Consulta gli schemi esatti delle richieste e delle risposte su /public/docs e /public/openapi.json.
Questa guida ti presenta tre percorsi: il modo più rapido per provare l’API (il playground della documentazione interattiva), il modo più semplice per eseguire i tuoi script (una credenziale API personale creata nell’app) e il flusso OAuth standard che userai per creare un’app destinata ad altri host.
L’accesso viene verificato in base alla proprietà e al diritto dell’assistente dell’alloggio. Una connessione PMS attiva è necessaria per le operazioni che ne dipendono, tra cui la gestione del calendario e la creazione di prenotazioni dirette. Le altre risorse non richiedono una connessione PMS solo per essere lette o modificate.
https://api.nowistay.com/public/v1/* richiedono un token di accesso OAuth2, inviato come Authorization: Bearer ....Apri https://api.nowistay.com/public/docs nel tuo browser. La pagina è una Swagger UI completa dell’API, con un playground OAuth integrato che registra automaticamente un client per te. Non serve scrivere codice per testare le chiamate.
Cmd+Shift+R su Mac, Ctrl+F5 su Windows)./public/docs, già autenticato.GET /public/v1/properties, clicca su Try it out, poi su Execute.Da qui puoi provare ogni endpoint con un clic, vedere l’esatto JSON restituito da Nowistay e copiare il comando cURL di qualsiasi chiamata. È il modo consigliato per esplorare l’API prima di scrivere codice.
Importante. Il client del playground esiste solo nel tuo browser. Va bene per i test, ma per un’integrazione reale dovresti creare una credenziale API personale o registrare il tuo client OAuth (entrambe le opzioni sono spiegate qui sotto).
Se stai automatizzando il tuo account (uno script di reportistica, una sincronizzazione con il tuo strumento di contabilità, una piccola dashboard), non hai affatto bisogno del flusso OAuth completo. Crea una credenziale API personale nell’app e scambiala con un token in una sola chiamata. Nessuna schermata di consenso, nessun refresh token da gestire.
Reporting script) e spunta solo i permessi necessari.Il tuo script scambia poi la credenziale con un token di accesso (valido un’ora) e chiama l’API:
curl -X POST https://api.nowistay.com/public/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "grant_type=client_credentials" \
--data-urlencode "client_id=YOUR_CLIENT_ID" \
--data-urlencode "client_secret=YOUR_CLIENT_SECRET"
Quando il token scade, richiedine uno nuovo nello stesso modo. In questo flusso non c’è alcun refresh token, ed è proprio questo il punto: due righe di codice, nulla da sorvegliare.
Puoi creare fino a 10 credenziali, ciascuna con il proprio nome e i propri permessi. Una credenziale legge e scrive solo i dati a cui il tuo account può accedere e richiede lo stesso abbonamento AI Channel Manager attivo del resto dell’API.
Non puoi modificare gli scope di un token o di una credenziale personale esistenti. Crea una credenziale sostitutiva con l’insieme completo dei permessi di cui la tua integrazione ha bisogno. I client, i token di accesso, i codici di autorizzazione e i refresh token esistenti mantengono le concessioni originali; non viene aggiunto alcun permesso automaticamente.
https://app.nowistay.com/hub/user/developer. Annota i permessi usati dall’integrazione esistente.calendar.write; per inviare messaggi serve messages.write; per richiedere il pagamento di una prenotazione servono sia bookings.write sia payments.write.POST /public/oauth/token con grant_type=client_credentials e le credenziali sostitutive. Controlla il valore scope restituito e testa un endpoint consentito da quegli scope. GET /public/v1/properties richiede specificamente properties.read.Rigenera chiave non aggiunge scope. Sostituisce solo la chiave segreta della stessa credenziale; la chiave precedente resta valida per 7 giorni. Aggiornare o richiedere un altro token di accesso non può ampliare la concessione originale. Gli scope di scrittura non includono automaticamente gli scope di lettura.
POST /public/oauth/register con l’insieme completo degli scope desiderati e i normali dati della tua applicazione. Una registrazione equivalente con esattamente lo stesso insieme di scope riutilizza il client corrispondente; un insieme di scope modificato crea una nuova registrazione. Salva le credenziali del client restituite.Nel playground della documentazione, aggiorna la pagina e autorizza di nuovo con gli scope richiesti. I nuovi permessi sono elencati con etichette leggibili e i loro identificatori in inglese, francese, spagnolo, tedesco, olandese e italiano.
L’API usa lo standard OAuth 2.1 con il flusso authorization code e PKCE. In una frase: l’utente apre una pagina di Nowistay e dà il suo consenso, tu ricevi un breve codice, lo scambi con un token di accesso e chiami l’API con quel token. I token scadono e possono essere rinnovati senza disturbare di nuovo l’utente.
I tre endpoint OAuth che userai:
/public/oauth/register (POST)/public/oauth/authorize (GET, reindirizzamento del browser)/public/oauth/token (POST)Puoi anche recuperare i metadati OAuth su /.well-known/oauth-authorization-server/public-api, che elenca ogni endpoint e funzionalità supportata.
Chiunque può registrare un client OAuth, quindi gli host hanno bisogno di un modo per distinguere un’app appena nata da un’integrazione consolidata. Ogni app appena registrata parte quindi come non verificata:
Stai creando qualcosa per più di 3 account? Scrivi all’assistenza indicando il nome della tua app, il sito web e il caso d’uso. Quando la tua app sarà verificata, l’avviso scompare e il limite di account viene tolto.
L’API REST supporta 25 scope, tra cui dieci permessi aggiuntivi per modifiche agli alloggi, messaggi, guide, conoscenza, creazione di ospiti, upsell e pagamenti. Seleziona solo i permessi di cui la tua integrazione ha bisogno.
properties.read: legge i dettagli e le impostazioni operative degli alloggi.properties.write: aggiorna i dettagli e le impostazioni operative degli alloggi.calendar.read: legge disponibilità, tariffe per notte e restrizioni di soggiorno.calendar.write: aggiorna disponibilità, tariffe per notte e restrizioni di soggiorno.bookings.read: legge prenotazioni, dettagli finanziari e lo stato sicuro delle richieste di pagamento.bookings.sensitive.read: include nelle risposte delle prenotazioni i dati di contatto degli ospiti, gli indirizzi postali e i codici di accesso; per le letture richiede anche bookings.read.bookings.write: crea e aggiorna prenotazioni dirette. Le richieste di pagamento e i rimborsi richiedono anche payments.write.booking_parameters.read: legge le definizioni e i valori dei parametri di prenotazione personalizzati.booking_parameters.write: crea e aggiorna definizioni e valori dei parametri.missions.read: legge missioni e report di completamento.missions.write: crea, aggiorna e assegna missioni.activity.read: legge i registri di attività degli alloggi.team_members.read: legge i membri del team, i dati di contatto e le assegnazioni agli alloggi.webhooks.read: legge le sottoscrizioni ai webhook.webhooks.write: crea, aggiorna, mette in pausa ed elimina le sottoscrizioni ai webhook.customers.read: legge le schede ospite, i dati di contatto e lo storico dei soggiorni.customers.write: crea schede ospite.upsells.read: legge il catalogo degli upsell e gli acquisti delle prenotazioni.payments.write: richiede il pagamento durante la creazione della prenotazione e dispone rimborsi totali o parziali per le cancellazioni; richiede anche bookings.write.messages.read: legge conversazioni e messaggi degli ospiti.messages.write: invia messaggi agli ospiti.guides.read: legge le guide di benvenuto e il contenuto delle pagine.guides.write: modifica le guide, crea e aggiorna pagine, cambia la posizione delle pagine e carica immagini.knowledge.read: legge le domande e risposte private sugli alloggi.knowledge.write: crea e aggiorna la conoscenza privata. La copia richiede anche knowledge.read.Gli otto scope REST predefiniti restano properties.read, calendar.read, bookings.read, booking_parameters.read, missions.read, activity.read, team_members.read e webhooks.read. I valori predefiniti non aggiornano i token esistenti.
bookings.write + payments.write. La cancellazione senza rimborso usa solo bookings.write.customers.read + bookings.read.upsells.read + bookings.read. Le letture del catalogo richiedono solo upsells.read.knowledge.read + knowledge.write.bookings.write + booking_parameters.write. Un PATCH solo di parametri mantiene booking_parameters.write e funziona anche sulle prenotazioni OTA.I nuovi endpoint di scrittura restituiscono risultati minimi dell’azione, a meno che il token non abbia anche lo scope di lettura pertinente. L’attuale oscuramento dei dati delle prenotazioni resta in vigore. Gli endpoint delle missioni e delle conversazioni includono il contesto della prenotazione correlata con i propri scope.
Questi esempi usano ID e credenziali segnaposto. Sostituiscili con i tuoi valori. Questo flusso è per le app dei partner; le credenziali personali usano client_credentials come mostrato sopra.
Chiama POST /public/oauth/register con i permessi di cui hai bisogno. Salva in modo sicuro i client_id e client_secret restituiti. L’esempio richiede letture di alloggi, prenotazioni e missioni.
curl -X POST https://api.nowistay.com/public/oauth/register \
-H "Content-Type: application/json" \
-d '{"clientName":"My 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"}'
Per un client pubblico senza backend, usa "tokenEndpointAuthMethod": "none" e PKCE, senza chiave segreta del client.
Genera un PKCE verifier, la sua challenge S256 e uno state casuale. Reindirizza l’utente all’endpoint di autorizzazione. L’URL seguente è su una sola riga; codifica i valori della query come URL.
https://api.nowistay.com/public/oauth/authorize?response_type=code&client_id=YOUR_CLIENT_ID&redirect_uri=https%3A%2F%2Fmy-app.example.com%2Foauth%2Fcallback&scope=properties.read%20bookings.read%20missions.read&state=RANDOM_STATE&code_challenge=BASE64URL_S256_HASH&code_challenge_method=S256
L’host accede, controlla i permessi e approva o nega l’accesso. In caso di approvazione, il callback contiene un code monouso e il tuo state. Rifiuta un callback il cui state non corrisponde.
https://my-app.example.com/oauth/callback?code=AUTHORIZATION_CODE&state=RANDOM_STATE
curl -X POST https://api.nowistay.com/public/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "grant_type=authorization_code" \
--data-urlencode "code=AUTHORIZATION_CODE" \
--data-urlencode "redirect_uri=https://my-app.example.com/oauth/callback" \
--data-urlencode "client_id=YOUR_CLIENT_ID" \
--data-urlencode "client_secret=YOUR_CLIENT_SECRET" \
--data-urlencode "code_verifier=ORIGINAL_PKCE_VERIFIER"
La risposta include access_token, token_type, expires_in, refresh_token e scope. Conserva i token in modo sicuro. I token di accesso durano normalmente un’ora; usa la scadenza restituita.
Questo esempio richiede properties.read. Leggi i campi data e pagination nella risposta.
curl "https://api.nowistay.com/public/v1/properties" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
curl -X POST https://api.nowistay.com/public/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "grant_type=refresh_token" \
--data-urlencode "refresh_token=YOUR_REFRESH_TOKEN" \
--data-urlencode "client_id=YOUR_CLIENT_ID" \
--data-urlencode "client_secret=YOUR_CLIENT_SECRET"
Salva il nuovo refresh token restituito dalla risposta di rinnovo. Se il rinnovo fallisce, riavvia l’autorizzazione. Il rinnovo mantiene gli scope concessi in precedenza. Le credenziali personali non hanno un refresh token: richiedi un nuovo token di accesso con client_credentials.
GET /public/v1/properties/{property_id}/calendar richiede calendar.read. Passa una data from e una to inclusive; una singola richiesta può coprire fino a 730 giorni.
GET /public/v1/properties/101/calendar?from=2026-12-18&to=2026-12-20
Ogni giorno può restituire availability, rate, minStay, maxStay, stopSell, closedToArrival, closedToDeparture, restricted e restrictionReasons. availability è l’inventario ancora vendibile dopo le prenotazioni confermate. I campi di restrizione spiegano perché una data o un’azione di check-in/check-out è limitata.
PATCH /public/v1/properties/{property_id}/calendar richiede calendar.write. La richiesta è parziale: invia solo i controlli da modificare, i campi omessi restano invariati.
{
"from": "2026-12-18",
"to": "2026-12-31",
"availability": 1,
"rate": 145.0,
"minStay": 2,
"maxStay": 14,
"stopSell": false,
"closedToArrival": false,
"closedToDeparture": false,
"daysOfWeek": [0, 1, 2, 3, 4]
}
daysOfWeek è facoltativo: 0 è lunedì e 6 è domenica. Omettilo per aggiornare ogni data dell’intervallo. La risposta riporta daysUpdated e l’aggiornamento normalizzato che è stato applicato. Le modifiche vengono sincronizzate tramite Nowistay PMS.
Le operazioni sul calendario richiedono la proprietà, il diritto dell’assistente e la gestione attiva del calendario di Nowistay. Per abilitare gli scope del calendario su un’integrazione esistente, segui Come aggiungere scope a un token API esistente qui sopra; rinnovare un token o rigenerare la sua chiave non basta.
I filtri supportati includono propertyId, propertyIds ripetuto, status, channel, fromDate e toDate. La paginazione JSON standard usa limit (massimo 100) e offset. I filtri per data delle prenotazioni mantengono la loro semantica di sovrapposizione: departure >= fromDate e arrival <= toDate.
curl "https://api.nowistay.com/public/v1/bookings?propertyId=101&fromDate=2026-12-01&toDate=2026-12-31&status=confirmed" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
curl "https://api.nowistay.com/public/v1/bookings/9001" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Richiede lo scope aggiuntivo bookings.sensitive.read. Senza di esso, email, phone e il codice della serratura intelligente vengono omessi.
Le modifiche principali alle prenotazioni richiedono bookings.write e una prenotazione diretta idonea. Le prenotazioni OTA restano di sola lettura per i campi principali. Un PATCH che contiene solo customParameters supporta anche le prenotazioni OTA e usa booking_parameters.write.
curl -X PATCH "https://api.nowistay.com/public/v1/bookings/9001" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"notes": "Guest requested a baby cot.",
"reservationNumber": "DIRECT-9001",
"silent": true
}'
Le richieste PATCH esistenti sulle prenotazioni hanno come valore predefinito silent=true. Imposta silent=false per attivare le consuete notifiche di aggiornamento. La creazione di una prenotazione ha come valore predefinito silent=false. I campi omessi restano invariati e i valori null supportati già esistenti continuano a svuotare i campi. La sincronizzazione della disponibilità resta parte dell’operazione condivisa.
I parametri di prenotazione personalizzati sono utili quando vuoi rispecchiare in ogni prenotazione di Nowistay i dati del tuo sistema.
curl -X POST "https://api.nowistay.com/public/v1/booking-parameters" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-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 YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"customParameters": {
"external_status": "ready"
}
}'
Entrambi gli esempi usano booking_parameters.write. Gli aggiornamenti misti, con campi principali e parametri, richiedono entrambi gli scope di scrittura sulle prenotazioni; se la validazione fallisce, entrambi restano invariati.
Invia null come valore per svuotare un campo personalizzato in una prenotazione.
Richiede missions.write. I flussi di assegnazione e notifica vengono eseguiti anche per le missioni create tramite API.
curl -X POST "https://api.nowistay.com/public/v1/missions" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"propertyId": 101,
"bookingId": 9001,
"missionType": "cleaning",
"title": "Checkout cleaning",
"scheduledAt": "2026-12-18T11:30:00Z",
"timezone": "Europe/Paris",
"assignedTeamMemberId": 301
}'
Richiede activity.read.
curl "https://api.nowistay.com/public/v1/properties/101/activity?limit=20" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Gli eventi sono raggruppati in tre categorie: booking, mission e automation (messaggi agli ospiti, eventi delle serrature intelligenti).
Tutti i percorsi di questa sezione sono relativi a /public/v1. Sostituisci gli ID di esempio con risorse di proprietà dell’account collegato. Lo schema OpenAPI elenca ogni campo, enum e forma di risposta supportati.
Usa GET /properties/{id} con properties.read e PATCH /properties/{id} con properties.write. Gli elenchi di alloggi accettano search. Le modifiche supportate comprendono nome, indirizzo, capacità, tipo di alloggio, link degli annunci, copertina, orari di check-in/out, termini ultimi di prenotazione e impostazioni predefinite di prezzo e soggiorno.
curl -X PATCH "https://api.nowistay.com/public/v1/properties/101" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"capacity": 4,
"defaultMinStay": 2,
"cutOffDays": 1
}'
POST /bookings richiede bookings.write, il diritto dell’assistente e una connessione PMS attiva. Includi le date, l’email e i dati dell’ospite, con i campi di prezzo e operativi supportati. requestPayment=true richiede inoltre payments.write e crea la prenotazione in attesa di pagamento.
curl -X POST "https://api.nowistay.com/public/v1/bookings" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"propertyId": 101,
"arrival": "2026-12-18",
"departure": "2026-12-20",
"guestFirstName": "Maya",
"guestLastName": "Martin",
"guestEmail": "maya@example.com",
"adults": 2,
"amount": "290.00",
"currency": "EUR",
"requestPayment": true
}'
La creazione può riuscire anche se la generazione del link di pagamento fallisce. La risposta contiene comunque la prenotazione salvata o il suo ID, con paymentRequest.sent=false e un errore esplicito. Controlla questo risultato prima di riprovare, per non creare una prenotazione duplicata. Un URL di checkout viene restituito solo da un’azione di richiesta di pagamento autorizzata.
Leggi GET /bookings/{id}/payment-request con bookings.read per lo stato sicuro della prenotazione e della richiesta di pagamento. Non restituisce gli URL di checkout. Questa versione non aggiunge un’API autonoma di amministrazione dei pagamenti.
Il PATCH esistente delle prenotazioni supporta reservationNumber, cancellationRefundMode (none, full o partial) e cancellationRefundAmount. Un rimborso esplicito totale o parziale per la cancellazione richiede sia bookings.write sia payments.write. La cancellazione senza rimborso richiede solo bookings.write.
curl -X PATCH "https://api.nowistay.com/public/v1/bookings/9001" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"status": "cancelled",
"cancellationRefundMode": "partial",
"cancellationRefundAmount": "50.00"
}'
Una prenotazione cancellata non dimostra che un rimborso sia stato completato. Controlla lo stato del pagamento prima di dire all’ospite che il rimborso è andato a buon fine. payments.write autorizza le richieste di pagamento e i rimborsi per le cancellazioni, non la modifica del prezzo di un checkout esistente.
POST /guests usa customers.write; la creazione di un ospite duplicato restituisce 409. Le letture esistenti dei clienti a livello di proprietario restano disponibili. Gli elenchi di ospiti accettano propertyId, propertyIds ripetuto e i valori orderBy supportati: created_at, updated_at, full_name, bookings_count, total_amount, last_stay. Aggiungi il prefisso - per l’ordine decrescente; il valore predefinito è -updated_at.
curl -X POST "https://api.nowistay.com/public/v1/guests" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"firstName": "Maya",
"lastName": "Martin",
"email": "maya@example.com",
"language": "en"
}'
GET /guests/{id}/bookings richiede sia customers.read sia bookings.read e restituisce lo storico dei soggiorni idonei.
GET /missions/{id} e GET /missions/{id}/report usano missions.read. Una missione valida senza report di completamento restituisce 200 con report: null. Gli elenchi di missioni accettano filtri inclusivi per data UTC programmata fromDate/toDate, propertyIds e teamMemberIds ripetuti, oltre ai filtri esistenti.
curl "https://api.nowistay.com/public/v1/missions?propertyIds=101&propertyIds=102&teamMemberIds=301&fromDate=2026-12-01&toDate=2026-12-31" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
GET /conversations supporta i filtri propertyId e bookingId. GET /conversations/{id}/messages legge lo storico dei messaggi. Entrambi richiedono messages.read. Invia una risposta con POST /messages e messages.write, indicando esattamente uno tra conversationId e bookingId. channelKind o threadChannelId facoltativi selezionano un canale; non fornire entrambi i selettori.
curl -X POST "https://api.nowistay.com/public/v1/messages" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"bookingId": 9001,
"message": "Hello Maya, your arrival instructions are ready."
}'
I messaggi seguono il normale percorso di consegna delle risposte dell’host, incluso l’instradamento delle prenotazioni con più camere. Un messaggio salvato ma con consegna fallita restituisce il suo ID e lo stato di consegna: controlla il risultato prima di riprovare. Gli allegati ai messaggi degli ospiti non sono supportati da questi endpoint.
Usa GET /properties/{id}/knowledge-questions e GET /properties/{id}/knowledge-questions/{questionId} con knowledge.read. Usa POST sulla raccolta e PATCH su una singola domanda con knowledge.write.
curl -X POST "https://api.nowistay.com/public/v1/properties/101/knowledge-questions" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"question": "Where is the recycling area?",
"answer": "In the courtyard, next to the bicycle shelter."
}'
POST /properties/{id}/knowledge-questions/copy tratta {id} come origine e richiede knowledge.read più knowledge.write. Invia targetPropertyIds per unire il contenuto ad altri alloggi. La copia non elimina né sovrascrive mai le risposte di destinazione; ogni destinazione viene validata prima che inizino le scritture.
curl -X POST "https://api.nowistay.com/public/v1/properties/101/knowledge-questions/copy" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"targetPropertyIds": [102, 103]
}'
GET/PATCH /properties/{id}/welcome-guide: legge o modifica la guida, comprese le introduzioni localizzate.GET/POST /properties/{id}/welcome-guide/pages: elenca o crea pagine.GET/PATCH /properties/{id}/welcome-guide/pages/{pageId}: legge o modifica una singola pagina e la sua posizione.POST /properties/{id}/welcome-guide/images: carica un’immagine da un URL pubblico supportato o da un input base64.Le letture richiedono guides.read; le scritture richiedono guides.write. Quando modifichi pagine strutturate, conserva i blocchi content/contents di EditorJS e i loro ID, la formattazione annidata e i contenuti multimediali. Le lingue omesse restano invariate. La sostituzione con testo semplice di una pagina strutturata viene rifiutata. I token delle guide e i link di accesso degli ospiti non vengono restituiti.
curl -X PATCH "https://api.nowistay.com/public/v1/properties/101/welcome-guide" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"intros": {
"en": "Welcome! Your practical information is below.",
"fr": "Bienvenue ! Retrouvez les informations pratiques ci-dessous."
}
}'
Il download delle immagini deve avvenire da indirizzi raggiungibili pubblicamente. I reindirizzamenti vengono controllati e i limiti di dimensione vengono applicati. Consulta lo schema della richiesta di immagine per i campi URL/base64 supportati e i relativi limiti.
GET /upsells richiede upsells.read. GET /bookings/{id}/upsell-purchases richiede sia upsells.read sia bookings.read. Questi endpoint sono di sola lettura.
curl "https://api.nowistay.com/public/v1/bookings/9001/upsell-purchases" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Aggiungi responseFormat=table agli elenchi di prenotazioni o missioni per ottenere columns, rows e pagination, con limit fino a 500. Il JSON standard resta il formato predefinito e mantiene il suo massimo di 100. Usa offset per recuperare le pagine successive. Più propertyIds vengono intersecati con propertyId se vengono forniti entrambi i filtri.
curl "https://api.nowistay.com/public/v1/bookings?propertyIds=101&propertyIds=102&fromDate=2026-12-01&toDate=2026-12-31&responseFormat=table&limit=500&offset=0" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Le tabelle delle prenotazioni usano bookings.read; le tabelle delle missioni usano missions.read. Le assegnazioni delle pulizie nel report delle prenotazioni richiedono inoltre missions.read e la presenza nelle conversazioni richiede messages.read. I filtri per data delle prenotazioni mantengono la semantica di sovrapposizione; i filtri per data delle missioni usano date UTC programmate.
Le route REST esistenti, i valori predefiniti del JSON standard, la paginazione, l’oscuramento dei dati delle prenotazioni, lo svuotamento tramite null supportato e i valori predefiniti delle notifiche restano disponibili. Le restrizioni delle prenotazioni legate ai pagamenti descritte sopra sono applicate da questa versione. REST e MCP condividono le operazioni sottostanti e i loro effetti collaterali, mentre i contratti degli strumenti MCP e il comportamento di anteprima/conferma restano invariati.
Una pagina di Nowistay contiene un documento EditorJS per lingua. L’array blocks definisce l’ordine di visualizzazione. Ogni oggetto di quell’array è un blocco; inserisci gli esempi seguenti dentro content.blocks o contents.<locale>.blocks. I valori degli esempi sono fittizi e vanno adattati al tuo alloggio.
Struttura comune: id è una stringa stabile, univoca all’interno del documento; conserva gli ID esistenti e assegna un nuovo ID a ogni nuovo blocco. type è il nome esatto del blocco, sensibile alle maiuscole. data è un oggetto i cui campi dipendono dal tipo. Conserva anche gli eventuali tunes e i metadati del documento restituiti da una lettura, invece di ricostruirli inutilmente.
Richiesta di creazione: POST /public/v1/properties/{id}/welcome-guide/pages con guides.write. Usa locale + title + content per una lingua, oppure titles + contents per più lingue. icon ha come valore predefinito info. position accetta start, end o after_page; quest’ultimo richiede afterPageId. Ecco il corpo completo di una richiesta in inglese e francese:
{
"titles": {
"en": "Arrival",
"fr": "Arrivée"
},
"contents": {
"en": {
"blocks": [
{
"id": "arrival001",
"type": "header",
"data": {
"text": "Getting here",
"level": 2
}
},
{
"id": "arrival002",
"type": "paragraph",
"data": {
"text": "Use the <b>main entrance</b>."
}
}
]
},
"fr": {
"blocks": [
{
"id": "arrival001",
"type": "header",
"data": {
"text": "Venir au logement",
"level": 2
}
},
{
"id": "arrival002",
"type": "paragraph",
"data": {
"text": "Utilisez l’<b>entrée principale</b>."
}
}
]
}
},
"position": "end"
}
data.text è il testo del titolo. Usa data.level: 2, in linea con l’editor della guida. Il titolo della pagina in sé va in title o titles, fuori dai blocchi.
{
"id": "guide00001",
"type": "header",
"data": {
"text": "Arrival / Arrivée",
"level": 2
}
}
data.text è una stringa. Usa il markup inline <b>, <i> e <a href="https://…"> per grassetto, corsivo e link. Esegui l’escape delle virgolette doppie all’interno delle stringhe JSON. Non inviare come content un’intera pagina HTML o del Markdown.
{
"id": "guide00002",
"type": "paragraph",
"data": {
"text": "<b>Wi-Fi</b>: GuestNetwork. <i>Welcome / Bienvenue !</i> <a href=\"https://example.com/\">Information</a>"
}
}
Usa style: unordered. items contiene oggetti, non stringhe. Ogni elemento ha content (testo formattato), meta (un oggetto) e items (un array di elementi figli, vuoto per una foglia). Ripeti la stessa struttura per l’annidamento.
{
"id": "guide00003",
"type": "list",
"data": {
"style": "unordered",
"meta": {},
"items": [
{
"content": "Kitchen / Cuisine",
"meta": {},
"items": [
{
"content": "Coffee machine / Machine à café",
"meta": {},
"items": []
}
]
}
]
}
}
Usa style: ordered con meta.counterType: numeric alla radice. Mantieni la stessa struttura degli elementi e gli array annidati di un elenco puntato.
{
"id": "guide00004",
"type": "list",
"data": {
"style": "ordered",
"meta": {
"counterType": "numeric"
},
"items": [
{
"content": "Close the windows / Fermez les fenêtres",
"meta": {},
"items": []
},
{
"content": "Return the keys / Rendez les clés",
"meta": {},
"items": []
}
]
}
}
Usa style: checklist. Metti lo stato iniziale booleano della casella in meta.checked di ogni elemento. È un contenuto della guida, non un report di completamento di una missione.
{
"id": "guide00005",
"type": "list",
"data": {
"style": "checklist",
"meta": {},
"items": [
{
"content": "Windows closed / Fenêtres fermées",
"meta": {
"checked": false
},
"items": []
}
]
}
}
data.text è la citazione, caption è la sua attribuzione (oppure una stringa vuota) e alignment è l’impostazione di allineamento dell’editor. Usa left; la vista dell’ospite applica un proprio layout per le citazioni.
{
"id": "guide00006",
"type": "quote",
"data": {
"text": "Please respect the neighbours / Merci de respecter le voisinage.",
"caption": "Your host / Votre hôte",
"alignment": "left"
}
}
Un separatore visivo ha un oggetto data vuoto. La sua posizione in blocks determina dove compare la separazione.
{
"id": "guide00007",
"type": "delimiter",
"data": {}
}
data.content è un array di righe; ogni riga è un array di stringhe di celle. Mantieni lo stesso numero di celle in ogni riga. Con withHeadings: true, la prima riga fornisce le intestazioni delle colonne. Usa false quando ogni riga contiene dati ordinari.
{
"id": "guide00008",
"type": "table",
"data": {
"withHeadings": true,
"content": [
[
"Service",
"Time / Horaire"
],
[
"Check-in / Arrivée",
"16:00"
],
[
"Check-out / Départ",
"10:00"
]
]
}
}
data.file.url è l’URL dell’immagine caricata, non un nome di file locale né una stringa base64. caption è una stringa; withBorder, withBackground e stretched sono booleani. Prima invia l’immagine con POST a /public/v1/properties/{id}/welcome-guide/images, poi inserisci in content.blocks l’editorJsImageBlock restituito. Conserva i campi restituiti e usa un ID di blocco univoco. L’URL qui sotto è puramente illustrativo: sostituiscilo con l’URL reale restituito.
{
"id": "guide00009",
"type": "image",
"data": {
"file": {
"url": "https://images.example.com/replace-with-uploaded-image.jpg"
},
"caption": "Entrance / Entrée",
"withBorder": false,
"withBackground": false,
"stretched": false
}
}
Usa service: youtube per un normale video di YouTube, oppure youtubeShort per uno Short. source è il suo URL originale; embed è l’URL di incorporamento YouTube corrispondente. width e height sono numeri e caption è una stringa. L’editor usa 580 × 320 per un video normale e 315 × 560 per uno Short. Sostituisci VIDEO_ID_11 in entrambi gli URL con lo stesso ID reale di 11 caratteri del video; per gli Shorts, il percorso di source è /shorts/VIDEO_ID_11. L’HTML arbitrario di un iframe non è il formato del blocco.
{
"id": "guide00010",
"type": "video",
"data": {
"service": "youtube",
"source": "https://www.youtube.com/watch?v=VIDEO_ID_11",
"embed": "https://www.youtube.com/embed/VIDEO_ID_11",
"width": 580,
"height": 320,
"caption": "Arrival instructions / Instructions d’arrivée"
}
}
embed usa gli stessi campi data di video. Conserva il tipo esistente quando modifichi una pagina; entrambi mostrano YouTube e YouTube Shorts. Non dare per scontato che ogni provider di embed supportato da EditorJS sia supportato da Nowistay.
{
"id": "guide00011",
"type": "embed",
"data": {
"service": "youtubeShort",
"source": "https://www.youtube.com/shorts/VIDEO_ID_11",
"embed": "https://www.youtube.com/embed/VIDEO_ID_11",
"width": 315,
"height": 560,
"caption": ""
}
}
Usa un oggetto data vuoto per inserire qui il catalogo degli upsell idonei. Prodotti, prezzi e disponibilità provengono dal catalogo configurato e dal contesto dell’ospite; non sono incorporati in questo blocco.
{
"id": "guide00012",
"type": "upsellCatalog",
"data": {}
}
data.itemId è l’ID numerico di un upsell esistente. Trova l’ID corretto con GET /public/v1/upsells usando upsells.read; sostituisci il 401 fittizio qui sotto. Mantieni l’ID originale a meno che tu non voglia scegliere intenzionalmente un altro prodotto. La scrittura della pagina usa guides.write; questo blocco non crea un prodotto, non imposta un prezzo e non lo acquista.
{
"id": "guide00013",
"type": "upsellProduct",
"data": {
"itemId": 401
}
}
Validazione REST: la creazione e l’aggiornamento delle pagine rifiutano con HTTP 422 i tipi di blocco non supportati e i dati malformati. Ogni lingua fornita viene controllata prima di qualsiasi scrittura, inclusi gli elementi di elenco annidati, le celle delle tabelle e i campi multimediali. L’errore identifica il documento e il blocco coinvolti. Gli ID restano facoltativi per i documenti esistenti; se forniti, devono essere stringhe non vuote e univoche. Metadati e formattazione vengono conservati. Questa validazione strutturale non verifica se un’immagine sia raggiungibile o se un upsell esista.
imageLibrary è il controllo di selezione delle immagini dell’editor, non un blocco galleria dell’API. Usa i blocchi image. linkPreview è un’impostazione del blocco (tunes), non un tipo di contenuto separato; conserva i dati esistenti. Non inventare blocchi html, code, button né provider video non documentati: l’accettazione di un oggetto JSON non garantisce che verrà mostrato nella guida.
Leggi prima GET /public/v1/properties/{id}/welcome-guide/pages/{pageId} con guides.read per ottenere content e contents. Lavora su una copia del documento completo per la lingua che stai modificando, cambia solo i blocchi interessati, poi invia il documento con PATCH allo stesso URL con guides.write. Inviare un solo blocco sostituisce il documento con quel singolo blocco; i blocchi non vengono uniti per id. Le lingue omesse restano invariate. Per spostare una pagina esistente usa order, non position.
I campi text e texts non sostituiscono il documento strutturato. Segui le indicazioni simpleTextUpdateAllowed, recommendedUpdateMode e recommendedUpdateField della risposta di lettura; una pagina strutturata rifiuta la sostituzione con testo semplice. I singoli esempi di questa sezione descrivono blocchi, non richieste PATCH complete per una pagina esistente. Rileggi la pagina dopo la modifica e controlla lingue, ID, link e contenuti multimediali. Con il solo guides.write, la risposta di scrittura è minimale; aggiungi guides.read per ricevere i dettagli.
Se non vuoi interrogare continuamente l’API per rilevare le modifiche, puoi iscriverti ai webhook. Nowistay chiamerà quindi un URL che indichi ogni volta che una prenotazione viene creata o aggiornata nell’alloggio, e invierà gli stessi dati di prenotazione restituiti da GET /public/v1/bookings/{id}.
Oggi sono supportati due eventi:
booking.created: una nuova prenotazione è stata registrata nell’alloggio.booking.updated: una prenotazione esistente è cambiata (date, stato, dati dell’ospite, codice della serratura intelligente e così via).Ogni webhook è legato a un singolo alloggio e puoi registrarne fino a tre per alloggio. Le consegne sono firmate (HMAC-SHA256), così puoi verificare che provengano davvero da Nowistay, vengono ritentate con backoff esponenziale in caso di errore e l’endpoint viene disattivato automaticamente se continua a fallire per più di 72 ore. I payload dei webhook non contengono campi sensibili degli ospiti (email, telefono, indirizzo, codice della serratura intelligente). Quando ti servono, chiama l’API con lo scope bookings.sensitive.read.
I dettagli completi sulla configurazione e sulla verifica della firma sono nell’articolo dedicato: API pubblica: ricevere webhook di prenotazione in tempo reale.
Quando raggiungi il limite, l’API restituisce 429 Rate limit exceeded. Rallenta e riprova dopo qualche secondo.
Ogni errore ha la stessa struttura, con un code stabile, un messaggio leggibile e un requestId che puoi includere nelle richieste di assistenza.
{
"error": {
"code": "validation_error",
"message": "The request contains an invalid value.",
"requestId": "example-request-id"
}
}
400: richiesta non valida (corpo malformato, campo mancante).
silent nelle scritture. Impostalo su true quando sincronizzi dati in blocco e non vuoi attivare notifiche agli ospiti.requestId nei tuoi log. Rende le richieste di assistenza molto più rapide da risolvere./public/openapi.json.Guide per gli host: leggi il blog.
Pronto a mettere la tua casa vacanza in pilota automatico?