Aller au contenu

Lokyzen · Développeurs

API REST v1

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.

Créer une clé API

L’essentiel

  • URL de base : https://lokyzen.com/api/v1
  • Authentification : en-tête Authorization: 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.
  • Droits (scopes) attribués à chaque clé : properties:read, calendar:write, rates:write, reservations:read, reservations:write, guests:read, guests:write, messages:read, messages:write, tasks:read, tasks:write, payments:read, payments:write, accounting:read, accounting:write, reviews:read, webhooks:write. Un droit manquant renvoie 403.
  • Limite : 120 requêtes par minute et par clé (429 au-delà).
  • Écritures idempotentes : envoyez un en-tête Idempotency-Key sur les POST, PATCH et PUT ; rejouer la requête avec la même clé (pendant 24 h) renvoie la même réponse sans doublon.
  • Montants en centimes d’euro (entiers), dates au format AAAA-MM-JJ, horodatages ISO 8601.
  • Pagination par curseur : les listes renvoient nextCursor ; passez-le en paramètre cursor pour la page suivante (null à la fin).
  • Erreurs : { "error": { "code": "…", "message": "…", "details": … } } avec le code HTTP correspondant (400, 401, 403, 404, 409, 429).

Points d’accès

Connexion

get/api/v1/metoute clé valide

Organisation et droits de la clé (test de connexion des connecteurs)

Logements

get/api/v1/propertiesproperties:read

Logements (équipements, situation), types de logement (pièces, lits, salles de bain), unités et plans tarifaires

Disponibilités

get/api/v1/room-types/{id}/availabilityproperties:read

Disponibilités, prix et restrictions par nuit (400 jours au plus)

ParamètreEmplacementTypeDescription
id *cheminuuid
from *requêtestringDate AAAA-MM-JJ
to *requêtestringDate AAAA-MM-JJ

Devis

post/api/v1/quotesreservations:read

Devis exact (mêmes calculs que le back-office) et disponibilité

ParamètreEmplacementTypeDescription
Idempotency-Keyen-têtestringRejouer la requête avec la même clé renvoie la même réponse sans doublon (24 h)
Corps de la requête (JSON Schema)
{
  "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
    },
    "ratePlanId": {
      "description": "Tarif (GET /properties) ; absent = tarif par défaut",
      "anyOf": [
        {
          "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)$"
        },
        {
          "type": "null"
        }
      ]
    },
    "promoCode": {
      "anyOf": [
        {
          "type": "string",
          "maxLength": 30
        },
        {
          "type": "null"
        }
      ]
    }
  },
  "required": [
    "roomTypeId",
    "checkIn",
    "checkOut",
    "adults"
  ]
}

Réservations

get/api/v1/reservationsreservations:read

Réservations (pagination par curseur, filtre de période, synchronisation incrémentale)

ParamètreEmplacementTypeDescription
fromrequêtestringSéjours qui se terminent après cette date
torequêtestringSéjours qui commencent avant cette date
statusrequêteinquiry | option | confirmed | cancelled | no_show | completed
updatedSincerequêtedate-timeModifiées depuis (ISO 8601) : synchronisation incrémentale
cursorrequêteuuid
limitrequêteinteger
post/api/v1/reservationsreservations:write

Créer une réservation (prix calculé par Lokyzen, restrictions de séjour appliquées)

ParamètreEmplacementTypeDescription
Idempotency-Keyen-têtestringRejouer la requête avec la même clé renvoie la même réponse sans doublon (24 h)
Corps de la requête (JSON Schema)
{
  "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
    },
    "ratePlanId": {
      "description": "Tarif (GET /properties) ; absent = tarif par défaut",
      "anyOf": [
        {
          "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)$"
        },
        {
          "type": "null"
        }
      ]
    },
    "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"
  ]
}
get/api/v1/reservations/{id}reservations:read

Une réservation

ParamètreEmplacementTypeDescription
id *cheminuuid
patch/api/v1/reservations/{id}reservations:write

Changer le statut (confirmer, annuler…) ; le remboursement éventuel n’est jamais exécuté automatiquement

ParamètreEmplacementTypeDescription
id *cheminuuid
Idempotency-Keyen-têtestringRejouer la requête avec la même clé renvoie la même réponse sans doublon (24 h)
Corps de la requête (JSON Schema)
{
  "type": "object",
  "properties": {
    "status": {
      "type": "string",
      "enum": [
        "confirmed",
        "cancelled",
        "no_show",
        "completed"
      ]
    },
    "reason": {
      "anyOf": [
        {
          "type": "string",
          "maxLength": 500
        },
        {
          "type": "null"
        }
      ]
    },
    "party": {
      "type": "string",
      "enum": [
        "guest",
        "host"
      ]
    }
  },
  "required": [
    "status"
  ]
}
patch/api/v1/reservations/{id}/stayreservations:write

Modifier le séjour (dates, logement, voyageurs) ; restrictions de séjour appliquées

ParamètreEmplacementTypeDescription
id *cheminuuid
Idempotency-Keyen-têtestringRejouer la requête avec la même clé renvoie la même réponse sans doublon (24 h)
Corps de la requête (JSON Schema)
{
  "type": "object",
  "properties": {
    "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"
    },
    "unitId": {
      "description": "Logement physique (GET /properties → roomTypes[].units) ; par défaut, celui de la réservation",
      "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)$"
    },
    "adults": {
      "type": "integer",
      "minimum": 1,
      "maximum": 50
    },
    "children": {
      "type": "integer",
      "minimum": 0,
      "maximum": 50
    },
    "reprice": {
      "default": false,
      "description": "Recalculer le prix (imposé si le type de logement ou le nombre de voyageurs change) ; sinon le prix convenu est conservé",
      "type": "boolean"
    }
  },
  "required": [
    "checkIn",
    "checkOut"
  ]
}
get/api/v1/reservations/{id}/messagesmessages:read

Messages échangés avec le voyageur de la réservation (hors notes internes)

ParamètreEmplacementTypeDescription
id *cheminuuid
cursorrequêteuuid
limitrequêteinteger
post/api/v1/reservations/{id}/messagesmessages:write

Envoyer un message au voyageur (visible dans la messagerie Lokyzen)

ParamètreEmplacementTypeDescription
id *cheminuuid
Idempotency-Keyen-têtestringRejouer la requête avec la même clé renvoie la même réponse sans doublon (24 h)
Corps de la requête (JSON Schema)
{
  "type": "object",
  "properties": {
    "body": {
      "type": "string",
      "minLength": 1,
      "maxLength": 10000
    },
    "channel": {
      "default": "auto",
      "description": "auto : canal de la plateforme, sinon e-mail, sinon SMS, sinon page voyageur",
      "type": "string",
      "enum": [
        "email",
        "sms",
        "whatsapp",
        "guest_page",
        "airbnb",
        "booking",
        "vrbo",
        "expedia",
        "google_vr",
        "auto"
      ]
    },
    "subject": {
      "anyOf": [
        {
          "type": "string",
          "maxLength": 200
        },
        {
          "type": "null"
        }
      ]
    }
  },
  "required": [
    "body"
  ]
}
get/api/v1/reservations/{id}/paymentspayments:read

Échéancier, paiements reçus, remboursements et solde

ParamètreEmplacementTypeDescription
id *cheminuuid
post/api/v1/reservations/{id}/paymentspayments:write

Enregistrer un paiement reçu hors Lokyzen (virement, espèces, chèque…)

ParamètreEmplacementTypeDescription
id *cheminuuid
Idempotency-Keyen-têtestringRejouer la requête avec la même clé renvoie la même réponse sans doublon (24 h)
Corps de la requête (JSON Schema)
{
  "type": "object",
  "properties": {
    "method": {
      "type": "string",
      "enum": [
        "cash",
        "bank_transfer",
        "card_terminal",
        "cheque_vacances",
        "ancv_connect",
        "cheque",
        "channel"
      ]
    },
    "amountCents": {
      "type": "integer",
      "minimum": 1,
      "maximum": 10000000
    },
    "receivedOn": {
      "description": "Obligatoire, sauf pour un chèque annoncé (chequeStatus expected)",
      "anyOf": [
        {
          "type": "string",
          "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
          "description": "Date AAAA-MM-JJ"
        },
        {
          "type": "null"
        }
      ]
    },
    "dueId": {
      "anyOf": [
        {
          "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)$"
        },
        {
          "type": "null"
        }
      ]
    },
    "note": {
      "anyOf": [
        {
          "type": "string",
          "maxLength": 500
        },
        {
          "type": "null"
        }
      ]
    },
    "chequeStatus": {
      "description": "Chèque ou chèques-vacances : expected (annoncé, hors du payé), received (reçu, à encaisser) ou cashed (encaissé, par défaut)",
      "anyOf": [
        {
          "type": "string",
          "enum": [
            "expected",
            "received",
            "cashed"
          ]
        },
        {
          "type": "null"
        }
      ]
    },
    "cashOn": {
      "description": "Date d'encaissement prévue, obligatoire pour expected et received : rappel aux gestionnaires ce jour-là",
      "anyOf": [
        {
          "type": "string",
          "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
          "description": "Date AAAA-MM-JJ"
        },
        {
          "type": "null"
        }
      ]
    },
    "cashedOn": {
      "description": "Date d'encaissement (cashed), par défaut receivedOn",
      "anyOf": [
        {
          "type": "string",
          "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
          "description": "Date AAAA-MM-JJ"
        },
        {
          "type": "null"
        }
      ]
    },
    "chequeReference": {
      "description": "N° du chèque et banque ; n° de ticket (card_terminal) ou de transaction (ancv_connect)",
      "anyOf": [
        {
          "type": "string",
          "maxLength": 100
        },
        {
          "type": "null"
        }
      ]
    }
  },
  "required": [
    "method",
    "amountCents"
  ]
}
post/api/v1/reservations/{id}/payment-linkspayments:write

Créer un lien de paiement sécurisé (valable 14 jours)

ParamètreEmplacementTypeDescription
id *cheminuuid
Idempotency-Keyen-têtestringRejouer la requête avec la même clé renvoie la même réponse sans doublon (24 h)
Corps de la requête (JSON Schema)
{
  "type": "object",
  "properties": {
    "dueId": {
      "description": "Échéance à régler ; sinon amountCents, sinon tout le solde",
      "anyOf": [
        {
          "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)$"
        },
        {
          "type": "null"
        }
      ]
    },
    "amountCents": {
      "anyOf": [
        {
          "type": "integer",
          "minimum": 100,
          "maximum": 9007199254740991
        },
        {
          "type": "null"
        }
      ]
    },
    "sendEmail": {
      "default": false,
      "description": "Envoyer aussi le lien au voyageur par e-mail",
      "type": "boolean"
    }
  }
}

Voyageurs

get/api/v1/guestsguests:read

Voyageurs (recherche par e-mail, synchronisation incrémentale)

ParamètreEmplacementTypeDescription
emailrequêtestring
updatedSincerequêtedate-timeModifiés depuis (ISO 8601) : synchronisation incrémentale
cursorrequêteuuid
limitrequêteinteger
post/api/v1/guestsguests:write

Créer un voyageur ; s’il existe déjà (même e-mail ou téléphone), sa fiche est complétée et renvoyée

ParamètreEmplacementTypeDescription
Idempotency-Keyen-têtestringRejouer la requête avec la même clé renvoie la même réponse sans doublon (24 h)
Corps de la requête (JSON Schema)
{
  "type": "object",
  "properties": {
    "firstName": {
      "type": "string",
      "minLength": 1,
      "maxLength": 80
    },
    "lastName": {
      "type": "string",
      "minLength": 1,
      "maxLength": 80
    },
    "email": {
      "anyOf": [
        {
          "type": "string",
          "maxLength": 200,
          "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"
        }
      ]
    },
    "address": {
      "anyOf": [
        {
          "type": "string",
          "maxLength": 300
        },
        {
          "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"
  ]
}
get/api/v1/guests/{id}guests:read

Un voyageur

ParamètreEmplacementTypeDescription
id *cheminuuid
patch/api/v1/guests/{id}guests:write

Modifier un voyageur (seuls les champs envoyés changent)

ParamètreEmplacementTypeDescription
id *cheminuuid
Idempotency-Keyen-têtestringRejouer la requête avec la même clé renvoie la même réponse sans doublon (24 h)
Corps de la requête (JSON Schema)
{
  "type": "object",
  "properties": {
    "firstName": {
      "type": "string",
      "minLength": 1,
      "maxLength": 80
    },
    "lastName": {
      "type": "string",
      "minLength": 1,
      "maxLength": 80
    },
    "email": {
      "anyOf": [
        {
          "type": "string",
          "maxLength": 200,
          "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"
        }
      ]
    },
    "landline": {
      "description": "Téléphone fixe (simple coordonnée, sans déduplication ni SMS)",
      "anyOf": [
        {
          "type": "string",
          "maxLength": 30
        },
        {
          "type": "null"
        }
      ]
    },
    "address": {
      "anyOf": [
        {
          "type": "string",
          "maxLength": 300
        },
        {
          "type": "null"
        }
      ]
    },
    "locale": {
      "type": "string",
      "enum": [
        "fr",
        "en",
        "es",
        "de",
        "it",
        "pt"
      ]
    },
    "country": {
      "anyOf": [
        {
          "type": "string",
          "minLength": 2,
          "maxLength": 2
        },
        {
          "type": "null"
        }
      ]
    },
    "notes": {
      "anyOf": [
        {
          "type": "string",
          "maxLength": 5000
        },
        {
          "type": "null"
        }
      ]
    },
    "tags": {
      "maxItems": 30,
      "type": "array",
      "items": {
        "type": "string",
        "minLength": 1,
        "maxLength": 40
      }
    },
    "marketingConsent": {
      "description": "Consentement marketing (horodaté, source « api »)",
      "type": "boolean"
    }
  }
}

Webhooks (REST hooks)

post/api/v1/webhookswebhooks:write

S’abonner à des événements (REST hooks Zapier / Make) ; le secret de signature n’est renvoyé qu’ici

ParamètreEmplacementTypeDescription
Idempotency-Keyen-têtestringRejouer la requête avec la même clé renvoie la même réponse sans doublon (24 h)
Corps de la requête (JSON Schema)
{
  "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",
          "reservation.checkin_completed",
          "payment.received",
          "payment.refunded",
          "guest.created",
          "message.received",
          "review.received",
          "task.created",
          "task.completed",
          "reservation.*"
        ]
      }
    },
    "description": {
      "anyOf": [
        {
          "type": "string",
          "maxLength": 200
        },
        {
          "type": "null"
        }
      ]
    },
    "source": {
      "default": "manual",
      "type": "string",
      "enum": [
        "zapier",
        "make",
        "manual"
      ]
    }
  },
  "required": [
    "url",
    "events"
  ]
}
get/api/v1/webhookswebhooks:write

Abonnements de l’organisation (sans le secret)

delete/api/v1/webhooks/{id}webhooks:write

Se désabonner

ParamètreEmplacementTypeDescription
id *cheminuuid

Calendrier (blocages)

get/api/v1/blocksproperties:read

Dates bloquées (travaux, usage du propriétaire…) qui chevauchent la période

ParamètreEmplacementTypeDescription
from *requêtestringDate AAAA-MM-JJ
to *requêtestringDate AAAA-MM-JJ
propertyIdrequêteuuid
cursorrequêteuuid
limitrequêteinteger
post/api/v1/blockscalendar:write

Bloquer des dates (fermées à la vente sur tous les canaux)

ParamètreEmplacementTypeDescription
Idempotency-Keyen-têtestringRejouer la requête avec la même clé renvoie la même réponse sans doublon (24 h)
Corps de la requête (JSON Schema)
{
  "type": "object",
  "properties": {
    "unitId": {
      "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)$",
      "description": "Logement physique (GET /properties → roomTypes[].units)"
    },
    "startDate": {
      "type": "string",
      "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      "description": "Date AAAA-MM-JJ"
    },
    "endDate": {
      "type": "string",
      "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      "description": "Exclu : premier jour de nouveau disponible"
    },
    "reason": {
      "default": "other",
      "type": "string",
      "enum": [
        "maintenance",
        "owner_use",
        "personal",
        "other"
      ]
    },
    "note": {
      "anyOf": [
        {
          "type": "string",
          "maxLength": 500
        },
        {
          "type": "null"
        }
      ]
    }
  },
  "required": [
    "unitId",
    "startDate",
    "endDate"
  ]
}
delete/api/v1/blocks/{id}calendar:write

Débloquer des dates

ParamètreEmplacementTypeDescription
id *cheminuuid

Tâches

get/api/v1/taskstasks:read

Tâches d’une période ou d’une réservation

ParamètreEmplacementTypeDescription
fromrequêtestringTâches dont la fenêtre se termine après cette date (obligatoire sans reservationId)
torequêtestringTâches qui commencent avant cette date (62 jours au plus après from)
propertyIdrequêteuuid
reservationIdrequêteuuid
providerIdrequêteuuid
statusrequêtetodo | assigned | in_progress | done | validated | cancelledPar défaut, toutes sauf annulées
cursorrequêteuuid
limitrequêteinteger
get/api/v1/tasks/{id}tasks:read

Une tâche (avec sa liste de points à vérifier)

ParamètreEmplacementTypeDescription
id *cheminuuid
post/api/v1/tasks/{id}/assigntasks:write

Assigner la tâche à un prestataire (notifié) ou la désassigner

ParamètreEmplacementTypeDescription
id *cheminuuid
Idempotency-Keyen-têtestringRejouer la requête avec la même clé renvoie la même réponse sans doublon (24 h)
Corps de la requête (JSON Schema)
{
  "type": "object",
  "properties": {
    "providerId": {
      "anyOf": [
        {
          "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)$"
        },
        {
          "type": "null"
        }
      ],
      "description": "null : désassigner"
    }
  },
  "required": [
    "providerId"
  ]
}
post/api/v1/tasks/{id}/completetasks:write

Marquer la tâche terminée (points obligatoires de la liste cochés)

ParamètreEmplacementTypeDescription
id *cheminuuid
Idempotency-Keyen-têtestringRejouer la requête avec la même clé renvoie la même réponse sans doublon (24 h)
Corps de la requête (JSON Schema)
{
  "type": "object",
  "properties": {
    "report": {
      "anyOf": [
        {
          "type": "string",
          "maxLength": 5000
        },
        {
          "type": "null"
        }
      ]
    }
  }
}

Prestataires

get/api/v1/providerstasks:read

Prestataires actifs (ménage, maintenance…)

Factures

get/api/v1/invoicesaccounting:read

Factures, avoirs et reçus émis (numérotation continue)

ParamètreEmplacementTypeDescription
fromrequêtestringÉmises à partir de cette date
torequêtestringÉmises avant cette date
typerequêteinvoice | credit_note | receipt | quittance
reservationIdrequêteuuid
cursorrequêteuuid
limitrequêteinteger
get/api/v1/invoices/{id}accounting:read

Une facture, un avoir ou un reçu

ParamètreEmplacementTypeDescription
id *cheminuuid
get/api/v1/invoices/{id}/pdfaccounting:read

PDF de la pièce (Factur-X pour les factures et avoirs)

ParamètreEmplacementTypeDescription
id *cheminuuid

Dépenses

get/api/v1/expensesaccounting:read

Dépenses des logements (réparations, fournitures…)

ParamètreEmplacementTypeDescription
fromrequêtestringDate AAAA-MM-JJ
torequêtestringDate AAAA-MM-JJ
propertyIdrequêteuuid
unbilledOnlyrequêtetrue | falseSeulement les dépenses pas encore reprises dans un relevé
cursorrequêteuuid
limitrequêteinteger
post/api/v1/expensesaccounting:write

Enregistrer une dépense (refacturable au propriétaire)

ParamètreEmplacementTypeDescription
Idempotency-Keyen-têtestringRejouer la requête avec la même clé renvoie la même réponse sans doublon (24 h)
Corps de la requête (JSON Schema)
{
  "type": "object",
  "properties": {
    "propertyId": {
      "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)$"
    },
    "date": {
      "type": "string",
      "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      "description": "Date AAAA-MM-JJ"
    },
    "label": {
      "type": "string",
      "minLength": 1,
      "maxLength": 200
    },
    "category": {
      "type": "string",
      "enum": [
        "repair",
        "supplies",
        "cleaning",
        "utilities",
        "tax",
        "other"
      ]
    },
    "amountCents": {
      "type": "integer",
      "minimum": 1,
      "maximum": 100000000,
      "description": "TTC"
    },
    "vatCents": {
      "default": 0,
      "type": "integer",
      "minimum": 0,
      "maximum": 9007199254740991
    },
    "rechargeable": {
      "default": false,
      "description": "Refacturée au propriétaire sur son relevé",
      "type": "boolean"
    },
    "markupBp": {
      "default": 0,
      "description": "Majoration refacturée, en points de base (1000 = 10 %)",
      "type": "integer",
      "minimum": 0,
      "maximum": 5000
    }
  },
  "required": [
    "propertyId",
    "date",
    "label",
    "category",
    "amountCents"
  ]
}

Relevés de gérance

get/api/v1/owner-statementsaccounting:read

Relevés de gérance mensuels des propriétaires

ParamètreEmplacementTypeDescription
periodrequêtestringMois AAAA-MM
statusrequêtedraft | sent | paid
ownerClientIdrequêteuuid
cursorrequêteuuid
limitrequêteinteger
get/api/v1/owner-statements/{id}/pdfaccounting:read

PDF du relevé de gérance

ParamètreEmplacementTypeDescription
id *cheminuuid

Prix par nuit

put/api/v1/rate-plans/{id}/overridesrates:write

Prix et restrictions par nuit sur une période (seuls les champs envoyés changent ; null rétablit la règle du plan)

ParamètreEmplacementTypeDescription
id *cheminuuid
Idempotency-Keyen-têtestringRejouer la requête avec la même clé renvoie la même réponse sans doublon (24 h)
Corps de la requête (JSON Schema)
{
  "type": "object",
  "properties": {
    "from": {
      "type": "string",
      "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      "description": "Date AAAA-MM-JJ"
    },
    "to": {
      "type": "string",
      "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      "description": "Exclu (comme pour les disponibilités) : 731 nuits au plus"
    },
    "weekdays": {
      "description": "Jours concernés, 1 = lundi … 7 = dimanche ; par défaut tous",
      "minItems": 1,
      "maxItems": 7,
      "type": "array",
      "items": {
        "type": "integer",
        "minimum": 1,
        "maximum": 7
      }
    },
    "priceCents": {
      "description": "Prix de la nuit ; null : revenir au prix du plan",
      "anyOf": [
        {
          "type": "integer",
          "minimum": 0,
          "maximum": 10000000
        },
        {
          "type": "null"
        }
      ]
    },
    "minStay": {
      "anyOf": [
        {
          "type": "integer",
          "minimum": 1,
          "maximum": 365
        },
        {
          "type": "null"
        }
      ]
    },
    "maxStay": {
      "anyOf": [
        {
          "type": "integer",
          "minimum": 1,
          "maximum": 365
        },
        {
          "type": "null"
        }
      ]
    },
    "closedToArrival": {
      "type": [
        "boolean",
        "null"
      ]
    },
    "closedToDeparture": {
      "type": [
        "boolean",
        "null"
      ]
    },
    "stopSell": {
      "description": "Fermer à la vente",
      "type": [
        "boolean",
        "null"
      ]
    }
  },
  "required": [
    "from",
    "to"
  ]
}

Avis

get/api/v1/reviewsreviews:read

Avis des voyageurs (site, espace voyageur et plateformes), note sur 100

ParamètreEmplacementTypeDescription
propertyIdrequêteuuid
sourcerequêtestringdirect, airbnb, booking…
sincerequêtedate-timeReçus depuis (ISO 8601)
cursorrequêteuuid
limitrequêteinteger

Exemple : créer une réservation

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

Webhooks

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.created
  • reservation.confirmed
  • reservation.updated
  • reservation.cancelled
  • reservation.checkin_completed
  • payment.received
  • payment.refunded
  • guest.created
  • message.received
  • review.received
  • task.created
  • task.completed

Enveloppe

{
  "id": "0190b3c4-…",
  "type": "reservation.created",
  "createdAt": "2027-07-01T09:30:00.000Z",
  "data": { … la ressource concernée (réservation, paiement, voyageur…) }
}

Signature

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)
}

Livraison et nouvelles tentatives

  • Une réponse 2xx vaut accusé de réception ; répondez vite (traitez en différé si besoin).
  • En cas d’échec, nouvelles tentatives après 1 min, 5 min, 30 min, 2 h, 6 h, 12 h puis 24 h ; la livraison est ensuite abandonnée (renvoi manuel possible depuis le journal).
  • Après 50 échecs consécutifs, l’abonnement est suspendu ; le réactiver remet le compteur à zéro.
  • Pour un abonnement créé par Zapier ou Make, une réponse 410 Gone supprime l’abonnement.