/api/v1/metoute clé valideOrganisation et droits de la clé (test de connexion des connecteurs)
Lokyzen · Développeurs
Connectez vos outils à Lokyzen : logements, disponibilités, devis, réservations, voyageurs et webhooks. Spécification complète au format OpenAPI 3.1 : /api/v1/openapi.json.
https://staging.lokyzen.com/api/v1Authorization: Bearer hl_<préfixe>_<secret>. Les clés se créent dans Lokyzen, menu Intégrations › API (rôle propriétaire ou administrateur) ; la clé complète n’est affichée qu’une fois.properties:read, reservations:read, reservations:write, guests:read, webhooks:write. Un droit manquant renvoie 403.Idempotency-Key sur les POST et PATCH ; rejouer la requête avec la même clé (pendant 24 h) renvoie la même réponse sans doublon.AAAA-MM-JJ, horodatages ISO 8601.nextCursor ; passez-le en paramètre cursor pour la page suivante (null à la fin).{ "error": { "code": "…", "message": "…", "details": … } } avec le code HTTP correspondant (400, 401, 403, 404, 409, 429)./api/v1/metoute clé valideOrganisation et droits de la clé (test de connexion des connecteurs)
/api/v1/propertiesproperties:readLogements et types de logement
/api/v1/room-types/{id}/availabilityproperties:readDisponibilités, prix et restrictions par nuit (400 jours au plus)
| Paramètre | Emplacement | Type | Description |
|---|---|---|---|
| id * | chemin | uuid | |
| from * | requête | string | Date AAAA-MM-JJ |
| to * | requête | string | Date AAAA-MM-JJ |
/api/v1/quotesreservations:readDevis exact (mêmes calculs que le back-office) et disponibilité
| Paramètre | Emplacement | Type | Description |
|---|---|---|---|
| Idempotency-Key | en-tête | string | Rejouer la requête avec la même clé renvoie la même réponse sans doublon (24 h) |
{
"type": "object",
"properties": {
"roomTypeId": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"checkIn": {
"type": "string",
"pattern": "^\\d{4}-\\d{2}-\\d{2}$",
"description": "Date AAAA-MM-JJ"
},
"checkOut": {
"type": "string",
"pattern": "^\\d{4}-\\d{2}-\\d{2}$",
"description": "Date AAAA-MM-JJ"
},
"adults": {
"type": "integer",
"minimum": 1,
"maximum": 50
},
"children": {
"default": 0,
"type": "integer",
"minimum": 0,
"maximum": 50
},
"promoCode": {
"anyOf": [
{
"type": "string",
"maxLength": 30
},
{
"type": "null"
}
]
}
},
"required": [
"roomTypeId",
"checkIn",
"checkOut",
"adults"
]
}/api/v1/reservationsreservations:readRéservations (pagination par curseur, filtre de période, synchronisation incrémentale)
| Paramètre | Emplacement | Type | Description |
|---|---|---|---|
| from | requête | string | Séjours qui se terminent après cette date |
| to | requête | string | Séjours qui commencent avant cette date |
| status | requête | inquiry | option | confirmed | cancelled | no_show | completed | |
| updatedSince | requête | date-time | Modifiées depuis (ISO 8601) : synchronisation incrémentale |
| cursor | requête | uuid | |
| limit | requête | integer |
/api/v1/reservationsreservations:writeCréer une réservation (prix calculé par Lokyzen, restrictions de séjour appliquées)
| Paramètre | Emplacement | Type | Description |
|---|---|---|---|
| Idempotency-Key | en-tête | string | Rejouer la requête avec la même clé renvoie la même réponse sans doublon (24 h) |
{
"type": "object",
"properties": {
"roomTypeId": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"checkIn": {
"type": "string",
"pattern": "^\\d{4}-\\d{2}-\\d{2}$",
"description": "Date AAAA-MM-JJ"
},
"checkOut": {
"type": "string",
"pattern": "^\\d{4}-\\d{2}-\\d{2}$",
"description": "Date AAAA-MM-JJ"
},
"adults": {
"type": "integer",
"minimum": 1,
"maximum": 50
},
"children": {
"default": 0,
"type": "integer",
"minimum": 0,
"maximum": 50
},
"status": {
"default": "confirmed",
"type": "string",
"enum": [
"option",
"confirmed"
]
},
"externalId": {
"description": "Identifiant dans votre système (unique)",
"anyOf": [
{
"type": "string",
"maxLength": 100
},
{
"type": "null"
}
]
},
"notes": {
"anyOf": [
{
"type": "string",
"maxLength": 5000
},
{
"type": "null"
}
]
},
"guest": {
"type": "object",
"properties": {
"firstName": {
"type": "string",
"minLength": 1,
"maxLength": 80
},
"lastName": {
"type": "string",
"minLength": 1,
"maxLength": 80
},
"email": {
"anyOf": [
{
"type": "string",
"format": "email",
"pattern": "^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
},
{
"type": "null"
}
]
},
"phone": {
"anyOf": [
{
"type": "string",
"maxLength": 30
},
{
"type": "null"
}
]
},
"locale": {
"default": "fr",
"type": "string",
"enum": [
"fr",
"en",
"es",
"de",
"it",
"pt"
]
},
"country": {
"anyOf": [
{
"type": "string",
"minLength": 2,
"maxLength": 2
},
{
"type": "null"
}
]
}
},
"required": [
"firstName",
"lastName"
]
}
},
"required": [
"roomTypeId",
"checkIn",
"checkOut",
"adults",
"guest"
]
}/api/v1/reservations/{id}reservations:readUne réservation
| Paramètre | Emplacement | Type | Description |
|---|---|---|---|
| id * | chemin | uuid |
/api/v1/reservations/{id}reservations:writeChanger le statut (confirmer, annuler…) ; le remboursement éventuel n’est jamais exécuté automatiquement
| Paramètre | Emplacement | Type | Description |
|---|---|---|---|
| id * | chemin | uuid | |
| Idempotency-Key | en-tête | string | Rejouer la requête avec la même clé renvoie la même réponse sans doublon (24 h) |
{
"type": "object",
"properties": {
"status": {
"type": "string",
"enum": [
"confirmed",
"cancelled",
"no_show",
"completed"
]
},
"reason": {
"anyOf": [
{
"type": "string",
"maxLength": 500
},
{
"type": "null"
}
]
}
},
"required": [
"status"
]
}/api/v1/guestsguests:readVoyageurs (recherche par e-mail)
| Paramètre | Emplacement | Type | Description |
|---|---|---|---|
| requête | string | ||
| cursor | requête | uuid | |
| limit | requête | integer |
/api/v1/guests/{id}guests:readUn voyageur
| Paramètre | Emplacement | Type | Description |
|---|---|---|---|
| id * | chemin | uuid |
/api/v1/webhookswebhooks:writeS’abonner à des événements (REST hooks Zapier / Make) ; le secret de signature n’est renvoyé qu’ici
| Paramètre | Emplacement | Type | Description |
|---|---|---|---|
| Idempotency-Key | en-tête | string | Rejouer la requête avec la même clé renvoie la même réponse sans doublon (24 h) |
{
"type": "object",
"properties": {
"url": {
"type": "string",
"format": "uri",
"description": "URL https:// qui recevra les événements (POST JSON signé)"
},
"events": {
"minItems": 1,
"type": "array",
"items": {
"type": "string",
"enum": [
"*",
"reservation.created",
"reservation.confirmed",
"reservation.updated",
"reservation.cancelled",
"payment.received",
"guest.created",
"message.received",
"review.received",
"task.completed",
"reservation.*"
]
}
},
"description": {
"anyOf": [
{
"type": "string",
"maxLength": 200
},
{
"type": "null"
}
]
},
"source": {
"default": "manual",
"type": "string",
"enum": [
"zapier",
"make",
"manual"
]
}
},
"required": [
"url",
"events"
]
}/api/v1/webhooks/{id}webhooks:writeSe désabonner
| Paramètre | Emplacement | Type | Description |
|---|---|---|---|
| id * | chemin | uuid |
Le prix est calculé par Lokyzen (mêmes règles que le back-office) ; obtenez roomTypeId via GET /properties et vérifiez le tarif avec POST /quotes.
curl -X POST https://staging.lokyzen.com/api/v1/reservations \
-H "Authorization: Bearer hl_xxxxxxxx_votre_cle" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 3f1c2b9e-commande-1234" \
-d '{
"roomTypeId": "0190a1b2-…",
"checkIn": "2027-07-14",
"checkOut": "2027-07-21",
"adults": 2,
"status": "confirmed",
"externalId": "CMD-1234",
"guest": { "firstName": "Camille", "lastName": "Martin", "email": "camille@example.com", "locale": "fr" }
}'Créez un abonnement dans Lokyzen (Intégrations › Webhooks) ou par l’API (POST /api/v1/webhooks, utilisé par les REST hooks Zapier et Make). Chaque événement est envoyé en POST JSON. Abonnez-vous à des événements précis, à une famille (reservation.*) ou à tous (*).
reservation.createdreservation.confirmedreservation.updatedreservation.cancelledpayment.receivedguest.createdmessage.receivedreview.receivedtask.completed{
"id": "0190b3c4-…",
"type": "reservation.created",
"createdAt": "2027-07-01T09:30:00.000Z",
"data": { … la ressource concernée (réservation, paiement, voyageur…) }
}En-tête Lokyzen-Signature: t=<unix>,v1=<signature>, où la signature est le HMAC-SHA256 (hexadécimal) de la chaîne t.corps calculé avec le secret de l’abonnement (whsec_…). Vérifiez-la sur le corps brut et refusez les horodatages trop anciens :
import { createHmac, timingSafeEqual } from 'node:crypto'
// body : corps brut de la requête (chaîne), avant JSON.parse
export function verifyLokyzen(body, header, secret, toleranceSec = 300) {
const parts = Object.fromEntries(header.split(',').map((p) => p.split('=')))
const t = Number(parts.t)
if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSec) return false
const expected = createHmac('sha256', secret).update(`${t}.${body}`).digest('hex')
const given = Buffer.from(parts.v1 ?? '', 'hex')
const wanted = Buffer.from(expected, 'hex')
return given.length === wanted.length && timingSafeEqual(given, wanted)
}