Référence de l'API
Chaque route servie par l'API, qui peut l'appeler, et comment fonctionnent la connexion, les permissions, les erreurs, les listes et les limites.
Pour le pack Full Stack
URL de base et format des réponses
Chaque route est servie sous le préfixe /api. En local, l'URL de base est http://localhost:8000/api. Sur un serveur, c'est l'adresse de votre API suivie de /api, la même valeur que lisent les deux frontends dans NEXT_PUBLIC_API_BASE_URL (Variables d'environnement). Les photos sont servies en dehors du préfixe, sur /media/….
Les routes du site sont publiques ; celles du tableau de bord demandent le jeton bearer d'un admin, et la plupart aussi une permission. Les corps de requête sont en JSON, sauf pour les fichiers téléversés. Chaque réponse arrive dans la même enveloppe :
{
"success": true,
"data": { },
"message": ""
}data contient le résultat. message est une courte phrase que certaines écritures renseignent, dans la langue de la requête, et vide sinon. Les prix sont des nombres décimaux dans la devise du bien.
La vérification de santé ne demande aucun jeton :
curl http://localhost:8000/api/health{"success":true,"data":{"status":"ok","database":"up"},"message":""}Quand la base de données ne peut pas être lue, elle répond quand même 200, avec "status":"degraded" et "database":"down". La vérification de santé de l'image Docker lit ce champ.
Erreurs
Un échec garde l'enveloppe, avec success: false et le statut HTTP :
{
"success": false,
"data": null,
"message": "…",
"errors": { "email": ["…"] }
}messageest une phrase dans la langue de la requête.errorsapparaît lors d'un échec de validation, avec les problèmes par champ, indexés par le chemin envoyé par le client (commetitle.en). Un champ inconnu dans un corps est refusé.- Une route protégée sans jeton, ou avec un jeton expiré, répond
401; un jeton sans la permission répond403. - Une requête au-delà d'une limite répond
429.
Listes et pagination
{ "data": [ ], "page": 1, "limit": 12, "total": 15, "totalPages": 2 }- Les biens, les demandes et les visites sont paginés avec
pageetpage_size: 12 par page par défaut sur le site (24 au maximum), 10 dans le tableau de bord (50 au maximum). Les listes du tableau de bord renvoient aussi leurs nombres par statut. - Les admins, les rôles et les paramètres sont paginés avec
pageetpage_count. - Sauf si la route a son propre ordre, les lignes arrivent de la plus récemment mise à jour à la plus ancienne, avec l'identifiant comme départage, si bien que la pagination est stable.
- Les filtres de biens du site sont validés : une valeur inconnue est refusée avec
400plutôt qu'ignorée, tandis qu'une clé que l'API ne lit pas est ignorée, si bien qu'un lien partagé avec des paramètres en trop fonctionne quand même.
Langue
Envoyez Accept-Language: ar pour des messages en arabe ; toute autre valeur répond en anglais. Les biens et les quartiers portent les deux langues sous la forme { "en": "…", "ar": "…" } quel que soit l'en-tête, et le client en choisit une.
Connexion
Se connecter en tant qu'admin
Terminalcurl -X POST http://localhost:8000/api/auth/login \ -H "Content-Type: application/json" \ -d '{"email":"admin@velra.example","password":"Admin@123"}'data.access_tokenest le jeton, avectoken_typevalantBeareret l'admin avec ses rôles et ses permissions. Le jeton dureJWT_EXPIRATION,7dpar défaut, etexpires_inrapporte cette valeur telle qu'elle est écrite.GET /api/auth/merenvoie l'admin connecté avec ses rôles et ses permissions.Appeler une route protégée
Terminalcurl http://localhost:8000/api/leads -H "Authorization: Bearer YOUR_TOKEN"
- Un e-mail inconnu et un mauvais mot de passe répondent tous deux
401avec le même message. - Dix connexions échouées depuis une même adresse en 15 minutes répondent
429jusqu'à ce que le plus ancien échec ait 15 minutes (RATE_LIMIT_LOGIN). Les connexions réussies ne sont pas comptées. - Il n'y a ni inscription ni route de déconnexion : les comptes viennent du seed ou de la gestion des admins, et un client se déconnecte en oubliant son jeton.
| Méthode | Chemin | Qui peut l'appeler | Rôle |
|---|---|---|---|
POST | /api/auth/login | N'importe qui | Connexion d'un admin : email, password |
GET | /api/auth/me | Tout administrateur connecté | L'admin connecté, ses rôles et ses permissions |
Permissions
Les routes du tableau de bord vérifient une permission nommée <area>.<action>. Un admin détient toutes les permissions de tous ses rôles, et une route qui en nomme plusieurs accepte n'importe laquelle. Les 31 permissions et les deux rôles du seed sont listés dans Admins, rôles et permissions.
Les biens sur le site
| Méthode | Chemin | Qui peut l'appeler | Rôle |
|---|---|---|---|
GET | /api/properties | N'importe qui | Les biens publiés. purpose (sale, rent), type (apartment, villa, townhouse), neighborhood (slug), min_price, max_price, bedrooms (0 pour les studios, sinon un minimum), amenities (slugs séparés par des virgules, tous requis), q (titre ou référence), sort (newest, price_asc, price_desc), page, page_size |
GET | /api/properties/featured | N'importe qui | Les biens à la une de la page d'accueil : les références du paramètre home_featured_references, dans l'ordre, ou les biens publiés marqués à la une quand aucune de ces références n'est publiée |
GET | /api/properties/facets | N'importe qui | Les biens publiés comptés par finalité, par type et par quartier, pour les filtres et la page d'accueil |
GET | /api/properties/lookup | N'importe qui | Les biens publiés par identifiant, pour les biens enregistrés et la comparaison : ?ids=1,2,3, 12 au maximum |
GET | /api/properties/:slug/similar | N'importe qui | Jusqu'à trois biens publiés similaires |
GET | /api/properties/:slug | N'importe qui | Un bien publié en entier, avec sa galerie, son quartier et sa pièce mise en scène publique |
Les quartiers et les paramètres de l'agence
| Méthode | Chemin | Qui peut l'appeler | Rôle |
|---|---|---|---|
GET | /api/neighborhoods | N'importe qui | Les quartiers marqués visibles, dans leur ordre de tri |
GET | /api/settings/public | N'importe qui | Les paramètres que le site affiche : agency_name, les slogans et descriptions dans les deux langues, contact_email, agency_city, currency, timezone, home_featured_references et home_staging_property_slug |
Le formulaire de contact et les demandes de visite
| Méthode | Chemin | Qui peut l'appeler | Rôle |
|---|---|---|---|
POST | /api/leads | N'importe qui | Le formulaire de contact : name, email, intent (buy, rent, other), client_token (un UUID v4), et en option phone, preferred_areas (slugs), budget, message (1000 caractères), property_id. Répond 201 avec { id, received_at } |
POST | /api/viewings | N'importe qui | Une demande de visite : property_id (un bien publié), name, email, preferred_date (YYYY-MM-DD), preferred_time (HH:MM, heure de l'agence), client_token, et en option phone, message. Répond 201 avec { reference, status, preferred_at, timezone } |
- Un
client_tokenrépété renvoie le reçu du premier envoi au lieu d'en stocker un second. - Un champ
companyrempli est traité comme un robot : la réponse paraît identique, et rien n'est stocké. - Une visite doit commencer au moins une heure à l'avance, à l'heure
Asia/Dubai; plus tôt, la réponse est400avecpreferred_time_too_soonsurpreferred_at. - Chaque adresse peut envoyer cinq de chaque en dix minutes ; le suivant répond
429.
Gérer les biens
| Méthode | Chemin | Qui peut l'appeler | Rôle |
|---|---|---|---|
GET | /api/properties/manage | Admins avec properties.view | Tous les biens, brouillons compris. purpose, type, status, q, page, page_size ; renvoie les counts de tous, des publiés et des brouillons |
GET | /api/properties/manage/:id | Admins avec properties.view | Un bien en entier, avec sa galerie et ses paires de mise en scène |
POST | /api/properties/manage | Admins avec properties.create | Créer un brouillon. Requis : title (en, ar), purpose, type, price, bedrooms, bathrooms, area_sqm |
PUT | /api/properties/manage/:id | Admins avec properties.edit | Modifier n'importe quel champ, galerie comprise (media, jusqu'à 40 éléments) |
PATCH | /api/properties/manage/:id/status | Admins avec properties.publish | Définir status : draft, published, sold, rented ou archived |
PUT | /api/properties/manage/:id/media | Admins avec properties.edit | Remplacer la galerie, dans l'ordre, avec un élément marqué is_cover |
DELETE | /api/properties/manage/:id | Admins avec properties.delete | Supprimer le bien |
Demandes et visites
| Méthode | Chemin | Qui peut l'appeler | Rôle |
|---|---|---|---|
GET | /api/leads | Admins avec leads.view | Les demandes. status, q, received_within_days, page, page_size ; avec les nombres par statut |
GET | /api/leads/:id | Admins avec leads.view | Une demande avec son bien, ses notes et sa visite |
PATCH | /api/leads/:id | Admins avec leads.edit | Définir status (new, contacted, qualified, closed) et notes |
GET | /api/viewings | Admins avec viewings.view | Les visites. status, q, scheduled_from, scheduled_to, page, page_size ; avec les nombres par statut |
GET | /api/viewings/:id | Admins avec viewings.view | Une visite avec sa demande et son bien |
PATCH | /api/viewings/:id | Admins avec viewings.edit | action (confirm, complete, cancel), confirmed_at (ISO 8601) et admin_notes. Une action depuis le mauvais statut répond 400 |
GET | /api/overview | Admins avec overview.view | La vue d'ensemble : nombres de publiés, nouvelles demandes, visites en attente de confirmation et à venir, lignes récentes, biens à la une et points de la carte |
Quartiers et paramètres
| Méthode | Chemin | Qui peut l'appeler | Rôle |
|---|---|---|---|
GET | /api/neighborhoods/manage | Admins avec neighborhoods.view | Tous les quartiers, masqués compris |
POST | /api/neighborhoods/manage | Admins avec neighborhoods.create | En ajouter un : name (en, ar), et en option slug, short_description, city, is_featured, sort_order, is_active, cover_url, cover_alt |
PUT | /api/neighborhoods/manage/:id | Admins avec neighborhoods.edit | En modifier un |
DELETE | /api/neighborhoods/manage/:id | Admins avec neighborhoods.delete | En supprimer un ; ses biens continuent d'exister sans quartier |
GET | /api/settings | Admins avec settings.view | Tous les paramètres. search, category, page, page_count |
GET | /api/settings/:key | Admins avec settings.view | Un paramètre par sa clé |
PATCH | /api/settings/:key | Admins avec settings.edit | Modifier la valeur d'un paramètre |
DELETE | /api/settings/:key | Admins avec settings.edit | Supprimer un paramètre |
Admins et rôles
| Méthode | Chemin | Qui peut l'appeler | Rôle |
|---|---|---|---|
GET | /api/admins | Admins avec admins.view | Les admins. email, name, phone, page, page_count |
GET | /api/admins/statistics | Admins avec admins.view | Les nombres pour la liste des admins |
GET | /api/admins/:id | Admins avec admins.view | Un admin, par identifiant ou nom d'utilisateur |
POST | /api/admins | Admins avec admins.create | Ajouter un admin : first_name, last_name, email, password et password_confirmation (6 caractères ou plus), en option phone |
PATCH | /api/admins/:id | Admins avec admins.edit | Modifier un admin |
PATCH | /api/admins/:id/roles | Admins avec admins.assign_roles | Définir les rôles d'un admin : role_ids |
DELETE | /api/admins/:id | Admins avec admins.delete | Supprimer un admin |
PATCH | /api/admins/profile | Tout administrateur connecté | Modifier ses propres first_name, last_name, email, phone, profile_picture ou country_id en tant qu'admin connecté. Un password ou role_ids dans le corps répond 400 : le mot de passe a sa propre route |
PATCH | /api/admins/profile/password | Tout administrateur connecté | Modifier son propre mot de passe en tant qu'admin connecté : current_password, password, password_confirmation |
GET | /api/roles | Admins avec roles.view | Les rôles. name, guard_name, created_from, created_to, page, page_count |
GET | /api/roles/statistics | Admins avec roles.view | Les nombres pour la liste des rôles |
GET | /api/roles/select | Admins avec roles.view | L'identifiant et le nom de chaque rôle, pour un sélecteur |
GET | /api/roles/permissions | Admins avec roles.view | Toutes les permissions, groupées par domaine |
GET | /api/roles/:id | Admins avec roles.view | Un rôle avec ses permissions |
POST | /api/roles | Admins avec roles.create | Ajouter un rôle |
PUT | /api/roles/:id | Admins avec roles.edit | Renommer ou décrire un rôle |
POST | /api/roles/:id/permissions | Admins avec roles.assign_permissions | Définir les permissions d'un rôle |
DELETE | /api/roles/:id | Admins avec roles.delete | Supprimer un rôle |
Notifications et fichiers téléversés
| Méthode | Chemin | Qui peut l'appeler | Rôle |
|---|---|---|---|
GET | /api/notifications | Tout administrateur connecté | Les 30 notifications les plus récentes de l'admin connecté |
PATCH | /api/notifications/read-all | Tout administrateur connecté | Toutes les marquer comme lues |
PATCH | /api/notifications/:id/read | Tout administrateur connecté | En marquer une comme lue |
DELETE | /api/notifications/:id | Tout administrateur connecté | En supprimer une |
POST | /api/helpers/upload | Tout administrateur connecté | Stocker un fichier (file en multipart, avec path pour le dossier, for pour le préréglage de taille comme property, et type). Les photos sont ré-encodées, sur 1920 pixels de large au maximum ; les vidéos sont acceptées en MP4, WebM, MOV ou M4V ; 150 Mo au maximum. Répond avec l'adresse du fichier stocké |
Un fichier téléversé n'a pas de permission propre : ce que devient le fichier est vérifié par la route qui l'enregistre. Les notifications sont conservées 30 jours.
Limites par adresse
| Route | Limite | Variable |
|---|---|---|
POST /api/auth/login | 10 connexions échouées par 15 minutes | RATE_LIMIT_LOGIN |
POST /api/leads | 5 par 10 minutes | Aucune |
POST /api/viewings | 5 par 10 minutes | Aucune |
Une requête au-delà d'une limite répond 429. Les compteurs vivent dans la mémoire de l'API : un redémarrage les efface. Derrière un reverse proxy, définissez TRUST_PROXY pour que chaque visiteur soit compté sur sa propre adresse.
L'assistant IA et ses conversations
Inclus avec votre achat. Connectez-vous pour le lire, ou ouvrez-le dans votre téléchargement.
La route de streaming de l'assistant, sa liste de modèles et les conversations enregistrées.
Studio de mise en scène
Inclus avec votre achat. Connectez-vous pour le lire, ou ouvrez-le dans votre téléchargement.
Les routes du studio : générations, enregistrement d'une paire mise en scène et son approbation.
Serveur MCP
Inclus avec votre achat. Connectez-vous pour le lire, ou ouvrez-le dans votre téléchargement.
L'endpoint MCP pour les agents de code et la façon dont il est autorisé.
Mises à jour en direct via WebSocket
Inclus avec votre achat. Connectez-vous pour le lire, ou ouvrez-le dans votre téléchargement.
Les namespaces Socket.IO qu'écoute le tableau de bord, leurs événements et la façon dont une connexion est autorisée.
Route du mode démo
Inclus avec votre achat. Connectez-vous pour le lire, ou ouvrez-le dans votre téléchargement.
La route qui n'existe que sur un build de démo public.