API OmniStay
Versione 1 · Ultimo aggiornamento: 22 ottobre 2026
Collega i tuoi altri software a OmniStay: contabilità, dashboard, strumento di manutenzione, Zapier o Make. L’API dà accesso ai tuoi alloggi, prenotazioni, incarichi, proprietari e al tuo team, e permette di agire: incarichi, preventivi, fatture, calendario, prezzi… I webhook avvisano i tuoi software appena arriva una prenotazione, un messaggio o un incarico. Anche la tua IA (ChatGPT, Claude, Gemini) si collega, tramite il server MCP.
In breve
- URL di base:
https://escale-roan.vercel.app/api/v1 - Formato: JSON in UTF-8. Le date sono nel formato
AAAA-MM-JJ(anno-mese-giorno), gli orariHH:MM(ora di Parigi), gli importi in euro. - Autenticazione: una chiave API del tuo account nell’header
Authorization: Bearer esk_…. - Permessi: ogni chiave è in sola lettura oppure in lettura e scrittura (per agire: creare incarichi e usare le 91 azioni).
- IA collegate: server MCP all’indirizzo
https://app.omnistay.ai/mcp, connessione OAuth o con chiave API (dettagli). - Limite: 120 chiamate al minuto per chiave.
Creare una chiave
- In OmniStay, apri Impostazioni › Chiavi API. Solo la titolare e gli amministratori dell’account possono accedervi.
- Dai alla chiave il nome del software da collegare e autorizza la scrittura solo se quel software deve agire in OmniStay.
- Copia subito la chiave: inizia con
esk_e viene mostrata una sola volta. OmniStay ne conserva solo un’impronta (hash). - Una chiave che non usi più, o che qualcun altro potrebbe aver visto: revocala. Smette subito di funzionare.
Autenticarsi
Ogni chiamata include la chiave. Per verificare che funzioni:
curl https://escale-roan.vercel.app/api/v1/me \
-H "Authorization: Bearer esk_VOTRE_CLE"
{
"data": {
"organization": { "id": "11111111-1111-4111-8111-111111111111", "name": "Les Clés du Canal" },
"key": { "name": "Comptabilité", "prefix": "esk_Ab12Cd", "scopes": ["read"] }
}
}
È accettato anche l’header X-Api-Key: esk_….
Risorse
| Metodo | Endpoint | Cosa restituisce |
|---|---|---|
| GET | /me | Il tuo account e la chiave usata |
| GET | /properties, /properties/{id} | Alloggi |
| GET | /bookings, /bookings/{id} | Prenotazioni |
| GET | /missions, /missions/{id} | Incarichi: pulizie, chiavi, manutenzione… |
| POST | /missions | Crea un incarico (chiave con permesso di scrittura) |
| GET | /actions | Le 91 azioni, con lo schema dei loro parametri |
| POST | /actions/{nom} | Esegue un’azione (chiave con permesso di scrittura per agire) |
| POST | /webhooks | Registra un URL per ricevere eventi (webhook) |
| GET | /webhooks, /webhooks/{id} | Le sottoscrizioni create con questa chiave |
| DELETE | /webhooks/{id} | Elimina una sottoscrizione |
| GET | /owners, /owners/{id} | Proprietari |
| GET | /team, /team/{id} | Team |
Alloggi
GET /properties
{
"data": [{
"id": "p1", "name": "Loft Canal Saint-Martin", "internal_name": "Valmy 3e G", "type": "appartement", "status": "active",
"address": { "street": "42 quai de Valmy", "zip": "75010", "city": "Paris" },
"surface_m2": 58,
"capacity": { "guests": 4, "double_beds": 1, "single_beds": 0, "sofa_beds_double": 1, "sofa_beds_single": 0 },
"check_in": { "from": "16:00", "until": "23:00", "mode": "lockbox" }, "check_out": "11:00",
"platforms": ["airbnb", "booking"], "base_price": 145, "cleaning_fee": 70,
"owner_id": "c1", "created_at": "2026-10-17", "updated_at": "2026-10-17T09:12:44.512Z"
}],
"total": 6, "limit": 100, "offset": 0
}
I codici di accesso (cassetta portachiavi, serratura) e il Wi-Fi non vengono mai restituiti dall’API.
Prenotazioni
GET /bookings?from=2026-10-01&to=2026-11-01&property_id=p1
| Filtro | Effetto |
|---|---|
from, to | Le prenotazioni che si sovrappongono al periodo: check-out dopo from, check-in prima di to |
property_id | Un solo alloggio |
status | confirmed ou cancelled |
updated_since | Solo ciò che è cambiato da una data e un’ora ISO 8601 (2026-10-17T09:00:00Z): utile per la sincronizzazione |
{
"data": [{
"id": "cx_8f2a", "property_id": "p1", "platform": "airbnb", "reference": "HMX4K2P9QA", "status": "confirmed",
"check_in": "2026-10-17", "check_out": "2026-10-21", "nights": 4, "arrival_time": "16:30", "departure_time": null,
"guest": { "first_name": "Camille", "last_name": "Laurent", "email": "camille@exemple.fr", "phone": "+33 6 12 34 56 78",
"language": "fr", "country": "France", "count": 2 },
"amounts": { "currency": "EUR", "guest_paid": 690.8, "accommodation": 600, "nightly": 150, "cleaning": 70, "linen": 15,
"tourist_tax": 20.8, "platform_fees": 103.85, "payout": 566.15, "tax_collected_by_platform": true },
"created_at": "2026-09-30", "updated_at": "2026-10-16T18:02:11.870Z"
}],
"total": 1, "limit": 100, "offset": 0
}
Il giorno di partenza (check_out) non è una notte prenotata. platform vale airbnb, booking, vrbo, expedia, direct o manual.
Incarichi
GET /missions?from=2026-10-20&to=2026-10-31&type=cleaning
Filtri: from e to (data dell’incarico, inclusi), property_id, member_id, type, status, updated_since.
{
"data": [{
"id": "cl_8f2a", "type": "cleaning", "title": "Ménage de fin de séjour", "description": null,
"property_id": "p1", "booking_id": "cx_8f2a", "member_id": "t1",
"date": "2026-10-21", "time": "11:00", "duration": "02:30", "pay": 55, "billed": 70, "status": "accepted",
"report": null, "created_at": "2026-09-30", "updated_at": "2026-10-16T18:02:12.004Z"
}],
"total": 1, "limit": 100, "offset": 0
}
| Campo | Valori |
|---|---|
type | cleaning (pulizie), keys (chiavi), diy, linen, plumbing, electricity, photo, delivery, pool, tour, decoration, pests, hvac, taxi, massage, food, babysitting, pets, housekeeper, other |
status | unassigned, offered (proposto), accepted, done (completato, da approvare), validated, cancelled |
pay, billed | Pagato a chi esegue l’intervento e riaddebitato al proprietario (euro) |
report | Dopo l’incarico: numero di foto, commento, durata in minuti, oggetti mancanti e danni |
Creare un incarico
Con una chiave che ha il permesso di scrittura. L’incarico viene proposto alla persona scelta (member_id), altrimenti al team dell’alloggio; la persona lo accetta nella sua app e l’incarico compare subito in OmniStay.
curl -X POST https://escale-roan.vercel.app/api/v1/missions \
-H "Authorization: Bearer esk_VOTRE_CLE" \
-H "Content-Type: application/json" \
-d '{ "type": "plumbing", "property_id": "p1", "date": "2026-10-18", "time": "09:00",
"member_id": "t2", "description": "Fuite sous l’évier de la cuisine" }'
| Campo | Obbligatorio | Predefinito |
|---|---|---|
property_id | Sì | — |
date | Sì | — |
type | No | cleaning |
time | No | Orario di check-out dell’alloggio per una pulizia, 16:00 per le chiavi, altrimenti 10:00 |
duration | No | Durata della pulizia dell’alloggio, altrimenti 02:00 |
pay, billed | No | Impostazioni dell’alloggio per una pulizia |
member_id, booking_id | No | Nessuno |
title, description | No | Il nome del tipo di incarico |
Risposta 201 con l’incarico creato, nello stesso formato di GET /missions.
Azioni
Tutto quello che l’Assistente IA sa fare in OmniStay passa anche dall’API: 91 azioni (preventivi, fatture, prenotazioni, calendario, prezzi, incarichi, team e assenze, proprietari, alloggi, messaggi, recensioni, depositi cauzionali, segnalazioni, danni e controversie, prospect, stime delle entrate, accoglienza degli ospiti e messaggi programmati, tassa di soggiorno, statistiche delle prenotazioni e previsioni…), con gli stessi controlli: permessi della persona che ha creato la chiave, registro, annullamento dall’app per 24 ore. L’elenco, con lo schema JSON dei parametri di ciascuna:
curl https://escale-roan.vercel.app/api/v1/actions \
-H "Authorization: Bearer esk_VOTRE_CLE"
{ "data": [{ "name": "creer_devis", "title": "Créer un devis", "module": "Facturation", "kind": "write", "confirmation": false,
"description": "…", "input_schema": { "type": "object", "properties": { … } },
"method": "POST", "path": "/api/v1/actions/creer_devis" }], "total": 91 }
Per eseguire un’azione, invia i suoi parametri in JSON:
curl -X POST https://escale-roan.vercel.app/api/v1/actions/creer_devis \
-H "Authorization: Bearer esk_VOTRE_CLE" \
-H "Content-Type: application/json" \
-d '{ "client": "Sophie Martin", "objet": "Ménage de printemps",
"lignes": [{ "designation": "Grand ménage", "prix_unitaire": 120 }] }'
{ "status": "done", "message": "Devis en brouillon pour Sophie Martin : « Ménage de printemps »…",
"data": { "id": "doc_…" }, "url": "https://app.omnistay.ai/app/#/facturation/document/doc_…", "journal_id": "…" }
- Risposta
201quando l’azione è eseguita ("status": "done"),200per una lettura ("status": "ok"). - Aggiungi
"dry_run": trueper vedere cosa farebbe l’azione, senza modificare nulla: risposta"status": "preview"con l’anteprima. - Le azioni con
"confirmation": trueinviano qualcosa o non si possono annullare (emettere una fattura, inviare un messaggio, calendario e prezzi inviati alle piattaforme, addebitare un deposito cauzionale…). Tramite l’API vengono eseguite appena chiamate: provale prima condry_run. - Le azioni con
"kind": "write"richiedono una chiave con permesso di scrittura. Nelle risposte non ci sono mai codici di accesso né password del Wi-Fi.
IA collegate (MCP)
OmniStay è un server MCP (Model Context Protocol): ChatGPT, Claude, Gemini, Claude Code, Gemini CLI o i tuoi agenti leggono e agiscono in OmniStay con le 91 azioni qui sopra, sotto forma di strumenti (tool). Gestire OmniStay da un’IA fa parte dell’opzione Assistente IA.
- URL:
https://app.omnistay.ai/mcp(HTTP «streamable», risposte JSON, senza sessione). - Versioni del protocollo: 2024-11-05, 2025-03-26, 2025-06-18, 2025-11-25 e 2026-07-28.
- Connessione OAuth 2.1 (ChatGPT, Claude, Gemini): discovery tramite
/.well-known/oauth-protected-resourcee/.well-known/oauth-authorization-server, registrazione dinamica (/oauth/register) o documento di metadati del client, PKCE S256 obbligatorio, token vincolati alla risorsa, rinnovo con rotazione. La persona accede, sceglie la sua attività e può autorizzare solo la lettura; scollega l’IA con un tocco in Impostazioni › Chiavi API. - Connessione con chiave API (Claude Code, Gemini CLI, i tuoi agenti): header
Authorization: Bearer esk_…. - Conferma: gli strumenti che inviano qualcosa o non si possono annullare hanno un parametro
confirmer. Senza questo parametro non fanno nulla e restituiscono un’anteprima che inizia con «Rien n’est fait» (nulla è stato fatto); l’IA la mostra alla persona, poi richiama lo strumento con"confirmer": truedopo il suo consenso. - Registro: ogni azione viene annotata in Impostazioni › Registro dell’IA, a nome della persona che ha collegato l’IA, e si può annullare per 24 ore. 120 chiamate al minuto per ogni IA collegata.
Claude Code:
claude mcp add --transport http omnistay https://app.omnistay.ai/mcp \
--header "Authorization: Bearer esk_VOTRE_CLE"
Gemini CLI, in ~/.gemini/settings.json:
{ "mcpServers": { "omnistay": { "httpUrl": "https://app.omnistay.ai/mcp",
"headers": { "Authorization": "Bearer esk_VOTRE_CLE" } } } }
ChatGPT, Claude e Gemini: i passaggi aggiornati sono in OmniStay, Impostazioni › Chiavi API.
Webhooks
OmniStay avvisa il tuo software appena succede qualcosa: invia un POST in JSON all’URL che indichi. Crea la sottoscrizione nell’app (Impostazioni › Integrazioni, con «Invia un test» e gli ultimi invii) o tramite l’API con una chiave, secondo il modello «REST Hooks».
| Evento | Quando |
|---|---|
booking.created | Arriva una prenotazione futura: da piattaforma, prenotazione diretta o inserita a mano. Una prenotazione fatta sul sito di un property manager o di un host viene inviata una volta pagata, mai finché è in attesa di pagamento (né se viene annullata prima) |
booking.updated | Date, alloggio, orari di check-in o check-out, ospite o importi modificati (più modifiche prima dell’invio: un solo invio, il più recente) |
booking.cancelled | Una prenotazione viene annullata |
precheckin.completed | L’ospite ha compilato il pre-check-in: data.precheckin (completed_at, guests, forms), mai le schedine alloggiati |
message.received | Un nuovo messaggio di un ospite, un invio per ogni messaggio (text, translation, sent_at) |
review.received | Una nuova recensione: kind vale review (piattaforma) o first_impression (app dell’ospite) |
incident.opened | Un ospite segnala un problema (acqua calda, chiavi, Wi-Fi, perdita…) |
mission.created, mission.accepted, mission.done | Un incarico futuro viene creato, preso da una persona del team, completato (con il suo report) |
invoice.issued | Una fattura, un acconto o una nota di credito riceve il suo numero: source vale invoicing (Fatturazione) o owner_statement (fattura mensile di un proprietario) |
lead.received | Qualcuno compila il modulo del tuo sito vetrina |
I soggiorni e gli incarichi passati, le recensioni e i messaggi vecchi, e ciò che aggiunge un’importazione da un software precedente non attivano nulla.
Cosa riceve il tuo URL
POST https://votre-outil.exemple.fr/omnistay
Content-Type: application/json; charset=utf-8
User-Agent: OmniStay-Webhooks/1.0
X-OmniStay-Event: booking.created
X-OmniStay-Event-Id: evt_6f1c0b7e2d4a4c1f9b3e8d5a7c2f1e09
X-OmniStay-Delivery: 1842
X-OmniStay-Signature: t=1792656000,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd
{
"id": "evt_6f1c0b7e2d4a4c1f9b3e8d5a7c2f1e09",
"type": "booking.created",
"created_at": "2026-10-22T09:14:03Z",
"test": false,
"organization": { "id": "11111111-1111-4111-8111-111111111111", "name": "Les Clés du Canal" },
"data": {
"id": "cx_8f2a", "property_id": "p1", "property": { "id": "p1", "name": "Loft Canal Saint-Martin" },
"platform": "airbnb", "reference": "HMX4K2P9QA", "status": "confirmed",
"check_in": "2026-10-24", "check_out": "2026-10-28", "nights": 4, "arrival_time": "16:30", "departure_time": null,
"guest": { "first_name": "Camille", "last_name": "Laurent", "email": "camille@exemple.fr", "phone": "+33 6 12 34 56 78",
"language": "fr", "country": "France", "count": 2 },
"amounts": { "currency": "EUR", "guest_paid": 690.8, "payout": 566.15, "…": "…" },
"created_at": "2026-10-22"
}
}
datariprende il formato dell’API (prenotazione, incarico…), con il nome dell’alloggio (property), della persona del team (member) o dell’ospite (guest). Mai codici di accesso, Wi-Fi, depositi cauzionali né schedine alloggiati.- Rispondi con un codice
2xxentro 8 secondi; i redirect non vengono seguiti. - Lo stesso evento può arrivare due volte (nuovo tentativo):
idpermette di ignorare un duplicato. L’ordine di arrivo non è garantito:created_atindica l’ordine. - «Invia un test», nell’app, invia un esempio dell’evento scelto con
"test": truee dati di esempio: ci sono tutti i campi, così Zapier o Make imparano la struttura dei dati.
Verificare la firma
L’header X-OmniStay-Signature vale t=<horodatage>,v1=<signature> (horodatage: il timestamp). La firma è l’HMAC-SHA256 (in esadecimale) di <t>.<corps brut> (corps brut: il corpo grezzo della richiesta), calcolato con il secret del webhook (whsec_…, fornito alla creazione e visibile nell’app). Rifiuta un timestamp più vecchio di 5 minuti.
import crypto from 'node:crypto';
// corps : le texte brut reçu, avant tout JSON.parse
function signatureValable(secret, entete, corps) {
const m = /^t=(\d+),v1=([0-9a-f]{64})$/.exec(entete || '');
if (!m || Math.abs(Date.now() / 1000 - Number(m[1])) > 300) return false;
const attendue = crypto.createHmac('sha256', secret).update(`${m[1]}.${corps}`).digest('hex');
return crypto.timingSafeEqual(Buffer.from(attendue), Buffer.from(m[2]));
}
Nuovi tentativi e disattivazione
- Senza una risposta
2xx: nuovo tentativo dopo 1 min, 5 min, 30 min, 2 ore e poi 8 ore (6 tentativi in tutto), con esattamente lo stesso corpo e lo stessoid. - 24 ore di errori consecutivi: il webhook viene disattivato. Si riattiva dall’app.
- Una risposta
410 Gonelo disattiva subito (modello REST Hooks). - Revocare una chiave disattiva i webhook che ha creato. La cronologia degli invii viene conservata per 30 giorni.
Creare una sottoscrizione tramite l’API
| Metodo | Endpoint | Effetto |
|---|---|---|
| POST | /webhooks | Crea una sottoscrizione: { "url": "https://…", "events": ["booking.created"], "name": "…" } (sono accettati anche target_url ed event). Risposta 201 con data e secret, fornito una sola volta dall’API |
| GET | /webhooks, /webhooks/{id} | Le sottoscrizioni create con questa chiave e l’elenco degli eventi (events) |
| DELETE | /webhooks/{id} | Elimina una sottoscrizione creata con questa chiave |
curl -X POST https://escale-roan.vercel.app/api/v1/webhooks \
-H "Authorization: Bearer esk_VOTRE_CLE" \
-H "Content-Type: application/json" \
-d '{ "url": "https://votre-outil.exemple.fr/omnistay", "events": ["booking.created", "booking.cancelled"] }'
Basta una chiave in sola lettura. Solo URL https:// (porta 443), mai un indirizzo IP, locale o interno; al massimo 20 webhook per account.
Zapier e Make
OmniStay non ha un’app ufficiale né su Zapier né su Make: il collegamento passa dai webhook (per ricevere gli avvisi) e dalla chiave API (per agire). I passaggi sono nell’app, Impostazioni › Integrazioni; la guida passo passo, con tre esempi (prenotazioni in Google Sheets, messaggi degli ospiti in Slack, incarico creato da un modulo), è nel centro assistenza: «Relier OmniStay à Zapier» e «Relier OmniStay à Make» (in francese).
| Ricevere gli avvisi | Agire in OmniStay | |
|---|---|---|
| Zapier | «Webhooks by Zapier» › «Catch Hook» (piani a pagamento di Zapier) | «Webhooks by Zapier» › «Custom Request»: Method, URL, Data (JSON) e, in Headers, Authorization: Bearer esk_… |
| Make | «Webhooks» › «Custom webhook» | «HTTP» › «Make a request»: Authentication type «API key» (chiave Bearer esk_… nell’header Authorization), corpo application/JSON |
Proprietari e team
GET /owners
{ "data": [{ "id": "c1", "civility": "Mme", "first_name": "Sophie", "last_name": "Martin", "email": "sophie@exemple.fr",
"phone": "06 12 34 56 78", "address": "8 rue Lepic, 75018 Paris", "commission": { "mode": "percent", "value": 20 },
"since": "2023-04-02", "property_ids": ["p1", "p2"] }], "total": 1, "limit": 100, "offset": 0 }
GET /team
{ "data": [{ "id": "t1", "first_name": "Fatima", "last_name": "B.", "role": "cleaning", "status": "active",
"property_ids": ["p1", "p2"] }], "total": 1, "limit": 100, "offset": 0 }
role vale cleaning, keys, maintenance o other. Gli ex membri del team non compaiono.
Elenchi e paginazione
Gli elenchi restituiscono data, total, limit e offset. Di default, 100 elementi; limit arriva fino a 500. Per la pagina successiva, aumenta offset: ?limit=100&offset=100. Le prenotazioni sono ordinate per data di arrivo, gli incarichi per data e ora.
Errori
In caso di errore, la risposta contiene un codice stabile per i tuoi programmi e un messaggio in francese:
{ "error": { "code": "read_only_key", "message": "Cette clé est en lecture seule : créez une clé avec le droit d’écriture." } }
| Stato | Codici | Significato |
|---|---|---|
| 400 | invalid_date, invalid_period, invalid_status, invalid_type, invalid_limit, invalid_offset, invalid_json | Un filtro o il corpo della richiesta non è valido |
| 401 | missing_key, invalid_key | Chiave assente, sconosciuta o revocata |
| 403 | read_only_key | La chiave non ha il permesso di scrittura |
| 404 | not_found | Endpoint o elemento non trovato |
| 405 | method_not_allowed | Metodo non supportato su questo endpoint |
| 422 | property_required, unknown_property, unknown_member, unknown_booking, invalid_time, invalid_duration, invalid_amount, invalid_text | L’incarico da creare non è valido |
| 403, 404, 409, 422 | read_only, forbidden, unknown_action, not_found, conflict, invalid_input, invalid_state, ambiguous, already_exists… | Azioni: permessi insufficienti, azione o elemento sconosciuto, elemento modificato nel frattempo (riprova), parametri da correggere, più elementi possibili (specifica meglio), già fatto. Il messaggio dice cosa fare. |
| 409, 422 | url_required, invalid_url, events_required, already_exists, too_many_webhooks | Webhook: URL mancante o rifiutato (solo https pubblico), nessun evento riconosciuto, URL già registrato, più di 20 webhook |
| 429 | rate_limited | Più di 120 chiamate in un minuto: riprova un po’ più tardi |
| 500, 503 | server_error, not_configured | Problema da parte nostra: riprova tra un attimo |
Limiti e sicurezza
- Una chiave dà accesso ai dati della tua attività: custodiscila come una password. Usala da un server o da uno strumento di automazione, mai in una pagina web o in un’app pubblica.
- Una chiave vede solo il proprio account. Non dà mai accesso ai codici di accesso, al Wi-Fi né ai metodi di pagamento; i depositi cauzionali si sbloccano o si addebitano solo tramite le azioni previste, annotate nel registro.
- I dati dei tuoi ospiti, proprietari e membri del team restano sotto la tua responsabilità: collega solo software affidabili e revoca una chiave appena non serve più.
- 120 chiamate al minuto per chiave, al massimo 20 chiavi attive per account.
- Gli endpoint della versione 1 non cambieranno. Le novità arriveranno sotto forma di nuovi campi o nuovi endpoint.
Se chiedi assistenza, indica il nome della chiave usata, mai la chiave stessa.