Documentation API

L'API Hou.la vous permet d'intégrer la création et la gestion de liens courts directement dans vos applications, scripts ou services.

Base URL :https://hou.la/api

1. Authentification

Toutes les requêtes à l'API doivent être authentifiées en utilisant une clé API. Vous pouvez créer et gérer vos clés API depuis votre espace Manager.

Incluez votre clé API dans l'en-tête X-API-Key de chaque requête :

X-API-Key: houla_sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Important : Ne partagez jamais votre clé API. Elle donne accès à votre compte et à toutes vos données.

OAuth 2.0 (Authorization Code + PKCE)

En plus de l'authentification par clé API, Hou.la supporte OAuth 2.0 avec le flux Authorization Code + PKCE (S256). Ce mécanisme est idéal pour les applications tierces (plugins WordPress, extensions Chrome, SaaS) qui ont besoin d'agir au nom d'un utilisateur.

Note : OAuth est recommandé pour les intégrations tierces. Pour les scripts serveur personnels, préférez l'authentification par clé API (X-API-Key).

Flux d'autorisation

Étape Endpoint Description
1GET /oauth/authorize Valider les paramètres et afficher la page de consentement (frontend)
2POST /oauth/authorize L'utilisateur accepte ou refuse les permissions demandées
3POST /oauth/token Échanger le code d'autorisation contre un access_token et un refresh_token

PKCE (Proof Key for Code Exchange)

PKCE S256 est obligatoire pour toutes les requêtes OAuth sur Hou.la. Voici comment générer le challenge :

// 1. Générer un code_verifier aléatoire
const codeVerifier = crypto.randomBytes(32).toString('base64url');

// 2. Dériver le code_challenge (SHA-256 + base64url)
const codeChallenge = crypto
  .createHash('sha256')
  .update(codeVerifier)
  .digest('base64url');

// 3. Construire l'URL d'autorisation
const authorizeUrl = `https://hou.la/oauth/authorize?` +
  `client_id=YOUR_CLIENT_ID&` +
  `redirect_uri=YOUR_REDIRECT_URI&` +
  `response_type=code&` +
  `scope=links:read links:write&` +
  `code_challenge=${codeChallenge}&` +
  `code_challenge_method=S256`;

Échange du code (Token Request)

Une fois le code d'autorisation reçu, échangez-le contre des tokens :

curl -X POST "https://hou.la/api/oauth/token" \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "authorization_code",
    "client_id": "YOUR_CLIENT_ID",
    "code": "AUTHORIZATION_CODE",
    "redirect_uri": "YOUR_REDIRECT_URI",
    "code_verifier": "YOUR_CODE_VERIFIER"
  }'

Réponse du token

{
  "access_token": "eyJhbGciOiJIUz...",
  "refresh_token": "dGhpcyBpcyBh...",
  "token_type": "Bearer",
  "expires_in": 3600
}

Rafraîchir un token

Lorsque l'access_token expire, utilisez le refresh_token pour en obtenir un nouveau :

curl -X POST "https://hou.la/api/oauth/token" \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "refresh_token",
    "client_id": "YOUR_CLIENT_ID",
    "refresh_token": "YOUR_REFRESH_TOKEN"
  }'

Scopes disponibles

Scope Permission
links:read Lecture des liens, tags et statistiques
links:write Création, modification et suppression de liens
ecommerce:write Gestion des liens e-commerce et tracking de conversions
products:sync Synchronisation du catalogue produits
orders:create Création de commandes e-commerce
orders:update Modification du statut des commandes

Gestion des applications connectées

Les utilisateurs authentifiés (via Bearer token) peuvent lister et révoquer les applications connectées à leur compte :

// Lister les applications connectées
curl "https://hou.la/api/oauth/apps" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"

// Révoquer une application
curl -X DELETE "https://hou.la/api/oauth/apps/CLIENT_ID" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"

Workspaces (multi-comptes)

Toutes les ressources (liens, tags, webhooks, domaines, etc.) sont rattachées à un workspace et non directement à un compte utilisateur. Chaque utilisateur dispose d'un workspace personnel créé automatiquement à l'inscription.

Pour cibler un workspace spécifique, ajoutez l'en-tête X-Workspace-Id à vos requêtes :

X-Workspace-Id: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

Si cet en-tête est omis, le workspace personnel par défaut de l'utilisateur est utilisé automatiquement.

Bon à savoir : Les clés API sont liées à un workspace. Les requêtes effectuées avec une clé API ciblent automatiquement le workspace associé, sans besoin de l'en-tête X-Workspace-Id.

Exemple avec workspace

curl -X POST "https://hou.la/api/link" \
  -H "X-API-Key: houla_sk_xxxxxxxx" \
  -H "X-Workspace-Id: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/page"
  }'

2. Créer un lien court

Authentification requise : Cet endpoint nécessite une clé API ou un token JWT. Consultez la section Authentification ci-dessus.

POST/link

Paramètres

ParamètreTypeRequis Description
urlstringOui L'URL longue à raccourcir
titlestringNon Un titre pour identifier le lien
keystringNon Une clé personnalisée (ex: "mon-lien")
utm_sourcestringNon Source de la campagne (ex: "google", "newsletter", "facebook")
utm_mediumstringNon Support marketing (ex: "cpc", "email", "social")
utm_campaignstringNon Nom de la campagne (ex: "soldes-ete-2026")
utm_termstringNon Mots-clés payés (pour les campagnes publicitaires)
utm_contentstringNon Contenu spécifique (ex: "bouton-header", "lien-footer")
utm_idstringNon Identifiant de campagne pour le suivi avancé
ephemeralDurationstringNonDurée de vie du lien éphémère. Valeurs : 1h, 6h, 12h, 24h, 48h
customExpiresAtstringNonDate d'expiration personnalisée (ISO 8601, ex: 2026-06-15T23:59:59.000Z). Mutuellement exclusif avec ephemeralDuration. La clé n'est pas recyclée.
passwordstringNon Mot de passe pour protéger l'accès au lien (1-100 caractères). Hashé avec bcrypt. Sécurité renforcée.
fbPixelIdstringNonFacebook Pixel ID (10-20 chiffres, ex: 123456789012345). Le pixel se déclenche lors du clic pour constituer une audience de retargeting.
googleTagIdstringNonGoogle Tag ID (format G-XXX, AW-XXX, DC-XXX ou UA-XXX). Supporte gtag.js.
tiktokPixelIdstringNonTikTok Pixel ID (format CXXX..., ex: CABCDEF1234567890). Le pixel se déclenche lors du clic pour le suivi TikTok Ads.
ogTitlestringNonTitre Open Graph personnalisé affiché lors du partage sur les réseaux sociaux (max 200 caractères)
ogDescriptionstringNonDescription Open Graph personnalisée affichée lors du partage (max 500 caractères)
ogImageUrlstringNonURL de l'image Open Graph (doit être une URL valide commençant par http:// ou https://)
tagIdsstring[]Non Liste d'identifiants de tags à associer au lien (UUID). Les tags doivent exister au préalable.
customDomainIdstringNon UUID du domaine personnalisé à utiliser pour le lien court. Laissez vide pour utiliser le domaine par défaut (hou.la).
maxHitsnumberNon Nombre maximum de clics autorisés sur le lien (entre 1 et 1 000 000). Une fois atteint, le lien expire automatiquement.
isCloakedbooleanNon Activer le Link Cloaking (<code class="code-inline">true</code>/<code class="code-inline">false</code>). Masque l'URL de destination dans la barre d'adresse du visiteur.
deepLinkIosstringNonSchéma URI iOS pour ouvrir l'app native (ex: instagram://user?username=monprofil). Mobile uniquement.
deepLinkAndroidstringNonIntent URL Android pour ouvrir l'app native (ex: intent://user?username=monprofil#Intent;scheme=instagram;package=com.instagram.android;end). Mobile uniquement.
deepLinkFallbackUrlstringNon URL de repli si l'app n'est pas installée (ex: lien App Store, Play Store ou page web). Si non renseigné, la redirection standard s'applique.
Variables UTM : Ces paramètres sont automatiquement ajoutés à l'URL de destination pour le suivi dans Google Analytics et autres outils d'analyse.
Liens éphémères :Si vous spécifiez ephemeralDuration, le lien expirera automatiquement après la durée indiquée. La clé sera alors recyclée et pourra être réutilisée.
Expiration personnalisée :Si vous spécifiez customExpiresAt (ISO 8601), le lien expirera à cette date précise. La clé n'est pas recyclée. Mutuellement exclusif avec ephemeralDuration.
Liens protégés :Si vous spécifiez password, le visiteur devra saisir le mot de passe avant d'être redirigé. Le mot de passe est hashé avec bcrypt (jamais stocké en clair). Sécurité renforcée.
Retargeting Pixels : Ajoutez vos pixels Facebook, Google ou TikTok pour constituer des audiences de reciblage. Les pixels se déclenchent sur une page intermédiaire lors du clic (invisible pour les bots/crawlers, qui reçoivent un 301 direct).

Exemple de requête

curl -X POST "https://hou.la/api/link" \
  -H "X-API-Key: houla_sk_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/ma-page-tres-longue",
    "title": "Ma campagne marketing",
    "utm_source": "newsletter",
    "utm_medium": "email",
    "utm_campaign": "promo-janvier-2026"
  }'

Exemple avec lien éphémère

curl -X POST "https://hou.la/api/link" \
  -H "X-API-Key: houla_sk_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/offre-limitee",
    "title": "Promo flash 24h",
    "ephemeralDuration": "24h"
  }'

Exemple avec expiration personnalisée

curl -X POST "https://hou.la/api/link" \
  -H "X-API-Key: houla_sk_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/evenement",
    "title": "Inscription ouverte jusqu'au 15 juin",
    "customExpiresAt": "2026-06-15T23:59:59.000Z"
  }'

Exemple avec lien protégé par mot de passe

curl -X POST "https://hou.la/api/link" \
  -H "X-API-Key: houla_sk_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/document-confidentiel",
    "title": "Document privé",
    "password": "secret123"
  }'

Réponse

201 Created

{
  "id": "abc123",
  "key": "xY7k9",
  "url": "https://example.com/ma-page-tres-longue",
  "shortUrl": "https://hou.la/xY7k9",
  "title": "Ma campagne marketing",
  "hasPassword": false,
  "isEphemeral": false,
  "hitsCount": 0,
  "flashsCount": 0,
  "createdAt": "2026-01-28T10:30:00Z",
  "status": "active"
}

Réponse (lien éphémère)

{
  "id": "def456",
  "key": "aB3cD",
  "url": "https://example.com/offre-limitee",
  "shortUrl": "https://hou.la/aB3cD",
  "title": "Promo flash 24h",
  "hasPassword": false,
  "isEphemeral": true,
  "ephemeralDuration": "24h",
  "expiresAt": "2026-01-29T10:30:00Z",
  "createdAt": "2026-01-28T10:30:00Z",
  "status": "active"
}

Réponse (expiration personnalisée)

{
  "id": "jkl012",
  "key": "mN4pQ",
  "url": "https://example.com/evenement",
  "shortUrl": "https://hou.la/mN4pQ",
  "title": "Inscription ouverte jusqu'au 15 juin",
  "hasPassword": false,
  "isEphemeral": false,
  "expiresAt": "2026-06-15T23:59:59.000Z",
  "createdAt": "2026-02-12T10:30:00Z",
  "status": "active"
}

Réponse (lien protégé)

{
  "id": "ghi789",
  "key": "zK8mP",
  "url": "https://example.com/document-confidentiel",
  "shortUrl": "https://hou.la/zK8mP",
  "title": "Document privé",
  "hasPassword": true,
  "isEphemeral": false,
  "hitsCount": 0,
  "flashsCount": 0,
  "createdAt": "2026-01-28T10:30:00Z",
  "status": "active"
}
QR Code :Pour générer un QR code, utilisez l'endpoint dédié GET /api/link/{id}/qrcode (voir section 5).

3. Vérifier la disponibilité d'une clé

GET/link/{key}/availability

Endpoint public : Aucune authentification requise.

Exemple de requête

curl -X GET "https://hou.la/api/link/mon-lien/availability"

Réponse

200 OK

{
  "available": true
}

4. Récupérer un lien

GET/link/{id}

Récupère les détails complets d'un lien par son UUID, incluant les statistiques des 90 derniers jours et les tags.

Exemple de requête

curl -X GET "https://hou.la/api/link/a1b2c3d4-e5f6-7890-abcd-ef1234567890" \
  -H "X-API-Key: houla_sk_xxxxxxxx"

Réponse

200 OK

{
  "id": "abc123",
  "key": "xY7k9",
  "url": "https://example.com/ma-page-tres-longue",
  "shortUrl": "https://hou.la/xY7k9",
  "title": "Ma campagne marketing",
  "hasPassword": false,
  "isEphemeral": false,
  "hitsCount": 42,
  "flashsCount": 5,
  "createdAt": "2026-01-28T10:30:00Z",
  "status": "active"
}

5. Récupérer le QR code d'un lien

GET/link/{id}/qrcode

Paramètres de requête

ParamètreTypeDéfaut Description
widthnumber300 Largeur en pixels (50-1000)
marginnumber2 Marge autour du QR code (0-10)
darkColorstring#000000 Couleur des modules (hex)
lightColorstring#FFFFFF Couleur de fond (hex)
errorCorrectionLevelstringM Niveau de correction : L, M, Q, H
formatstringpng Format de sortie : png ou svg

Exemple de requête

curl -X GET "https://hou.la/api/link/a1b2c3d4-e5f6-7890-abcd-ef1234567890/qrcode?width=500&darkColor=%23FF5722" \
  -H "X-API-Key: houla_sk_xxxxxxxx"

Réponse (PNG)

200 OK

{
  "base64": "iVBORw0KGgoAAAANSUhEUgAA...",
  "dataUrl": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..."
}

Réponse (SVG)

{
  "svg": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 300 300\">...</svg>"
}

6. Lister vos liens

GET/link

Paramètres de requête

ParamètreTypeDéfaut Description
pagenumber1 Numéro de la page
limitnumber20 Nombre de résultats par page (max: 100)

Exemple de requête

curl -X GET "https://hou.la/api/link?page=1&limit=10" \
  -H "X-API-Key: houla_sk_xxxxxxxx"

Réponse

200 OK

{
  "data": [
    {
      "id": "abc123",
      "key": "xY7k9",
      "url": "https://example.com/page1",
      "shortUrl": "https://hou.la/xY7k9",
      "title": "Lien 1",
      "hasPassword": false,
      "isEphemeral": false,
      "hitsCount": 42,
      "createdAt": "2026-01-28T10:30:00Z"
    },
    ...
  ],
  "total": 55,
  "page": 1,
  "pageCount": 6,
  "count": 10
}
Tri : Utilisez le paramètre <code class='code-inline'>sort</code> au format <code class='code-inline'>champ,direction</code> (ex: <code class='code-inline'>createdAt,DESC</code>). Champs disponibles : createdAt, hitsCount, title.

7. Modifier un lien

PATCH/link/{id}

Paramètres

ParamètreType Description
urlstring La nouvelle URL de destination
titlestring Le nouveau titre du lien
passwordstringNouveau mot de passe (1-100 caractères), ou null pour retirer la protection
isEphemeralboolean Activer/désactiver le mode éphémère
ephemeralDurationstringDurée éphémère : 1h, 6h, 12h, 24h, 48h
customExpiresAtstringDate d'expiration personnalisée (ISO 8601), ou null pour retirer l'expiration
fbPixelIdstringFacebook Pixel ID (10-20 chiffres), ou null pour retirer le pixel
googleTagIdstringGoogle Tag ID (G-XXX, AW-XXX, DC-XXX, UA-XXX), ou null pour retirer
tiktokPixelIdstringTikTok Pixel ID (CXXX...), ou null pour retirer
ogTitlestring | nullNouveau titre Open Graph, ou null pour retirer
ogDescriptionstring | nullNouvelle description Open Graph, ou null pour retirer
ogImageUrlstring | nullNouvelle URL d'image Open Graph, ou null pour retirer
tagIdsstring[] | nullListe d'identifiants de tags (UUID) à associer au lien, ou null pour retirer tous les tags
maxHitsnumber | nullNombre maximum de clics autorisés (1 à 1 000 000), ou null pour retirer la limite
isCloakedbooleanActiver ou désactiver le Link Cloaking (true/false)
deepLinkIosstring | nullSchéma URI iOS, ou null pour supprimer
deepLinkAndroidstring | nullIntent URL Android, ou null pour supprimer
deepLinkFallbackUrlstring | null URL de repli, ou <code class="code-inline">null</code> pour supprimer

Exemple de requête

curl -X PATCH "https://hou.la/api/link/abc123" \
  -H "X-API-Key: houla_sk_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Nouveau titre",
    "url": "https://example.com/nouvelle-destination"
  }'

Réponse

200 OK

{
  "id": "abc123",
  "key": "xY7k9",
  "url": "https://example.com/nouvelle-destination",
  "shortUrl": "https://hou.la/xY7k9",
  "title": "Nouveau titre",
  "hasPassword": false,
  "updatedAt": "2026-01-28T14:00:00Z"
}

8. Supprimer un lien

DELETE/link/{id}

Supprime un lien (suppression logique). La clé peut être libérée pour réutilisation.

Cette requête ne nécessite pas de corps (body). Seul l'UUID dans l'URL est requis.

Exemple de requête

curl -X DELETE "https://hou.la/api/link/a1b2c3d4-e5f6-7890-abcd-ef1234567890" \
  -H "X-API-Key: houla_sk_xxxxxxxx"

Réponse

200 OK

{
  "success": true,
  "message": "Lien supprimé avec succès"
}
Alternative :Vous pouvez également supprimer vos liens depuis le tableau de bord.

9. Upload d’image OG

Uploadez une image personnalisée qui sera optimisée (1200×630, WebP) et stockée sur notre CDN. L'image remplace automatiquement le champ ogImageUrl du lien.

Uploader une image

POST/manager/link/{id}/og-image

Le body doit être de type <code class="code-inline">multipart/form-data</code> avec un champ <code class="code-inline">file</code> (JPG, PNG ou WebP, max 8 Mo).

Exemple de requête

curl -X POST "https://hou.la/api/manager/link/abc123/og-image" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -F "file=@my-og-image.jpg"

Réponse

200 OK

{
  "ogImageUrl": "https://r2.hou.la/og-images/user123/link456/abc.webp",
  "ogImageR2Key": "og-images/user123/link456/abc.webp"
}

Supprimer l'image uploadée

DELETE/manager/link/{id}/og-image

curl -X DELETE "https://hou.la/api/manager/link/abc123/og-image" \
  -H "Authorization: Bearer YOUR_TOKEN"

204 No Content

Crawler les meta OG

POST/manager/link/{id}/og-crawl

Re-crawle les meta Open Graph depuis l’URL de destination du lien. Utile pour mettre à jour les données OG après modification de la page cible.

curl -X POST "https://hou.la/api/manager/link/abc123/og-crawl" \
  -H "Authorization: Bearer YOUR_TOKEN"

Réponse

200 OK

{
  "ogTitle": "Page Title",
  "ogDescription": "Page description from meta tags",
  "ogImageUrl": "https://example.com/og-image.jpg",
  "ogCrawlStatus": "success",
  "ogCrawledAt": "2026-02-16T10:30:00.000Z"
}

Prévisualiser les meta OG d’une URL

POST/manager/link/og-crawl-url

Crawle une URL sans créer de lien, pour prévisualiser les meta OG qui seront extraites.

ParamètreTypeRequis Description
urlstringOui URL à crawler (ex : https://example.com)
curl -X POST "https://hou.la/api/manager/link/og-crawl-url" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/my-page"
  }'

Réponse

200 OK

{
  "ogTitle": "My Page Title",
  "ogDescription": "Description from meta tags",
  "ogImageUrl": "https://example.com/image.jpg"
}

Récupérer les données OG d’un lien

GET/manager/link/{id}/og-preview

Retourne les meta OG stockées pour un lien (titre, description, image, statut du crawl).

curl -X GET "https://hou.la/api/manager/link/abc123/og-preview" \
  -H "Authorization: Bearer YOUR_TOKEN"

Réponse

200 OK

{
  "ogTitle": "Page Title",
  "ogDescription": "Page description",
  "ogImageUrl": "https://r2.hou.la/og-images/user/link/abc.webp",
  "ogCrawlStatus": "manual",
  "ogCrawledAt": "2026-02-16T10:30:00.000Z"
}
Auto-détection : Si aucun champ OG n’est fourni à la création, le système crawle automatiquement l’URL de destination pour extraire les meta OG existantes (og:title, og:description, og:image avec fallbacks sur twitter:title, meta description, etc.).
Bots sociaux : Lorsqu’un bot social (facebookexternalhit, Twitterbot, LinkedInBot, WhatsApp, Telegram, Discord, etc.) accède au lien court, il reçoit une page HTML avec les meta OG au lieu d’une redirection 301. Les visiteurs humains sont toujours redirigés normalement.

10. Smart Routing (règles de redirection)

Le Smart Routing permet de définir des règles de redirection conditionnelle sur vos liens. Chaque règle contient un libellé, une URL de destination, des conditions (pays, appareil, langue, navigateur, OS, première visite) et un poids optionnel pour l'A/B testing.

Lister les règles d'un lien

GET/link/{linkId}/rules

curl -X GET "https://hou.la/api/link/abc123/rules" \
  -H "X-API-Key: houla_sk_xxxxxxxx"

Réponse

200 OK

[
  {
    "id": "rule-1",
    "linkId": "abc123",
    "label": "Visiteurs français mobile",
    "destinationUrl": "https://example.fr/page-fr",
    "matchType": "all",
    "priority": 0,
    "weight": 100,
    "isActive": true,
    "conditions": [
      {
        "field": "country",
        "operator": "equals",
        "value": "FR"
      }
    ]
  }
]

Créer une règle

POST/link/{linkId}/rules

Paramètres

ParamètreTypeRequis Description
labelstringOui Libellé de la règle (max 100 caractères)
destinationUrlstringOui URL de destination si la règle correspond
matchTypestringNonall (défaut) = toutes les conditions, any = au moins une
weightnumberNon Poids pour l'A/B testing (0-100). Si des règles ont des poids, le trafic est réparti proportionnellement.
isActivebooleanNon Activer/désactiver la règle (défaut: true)
conditionsarrayOui Liste de conditions (voir ci-dessous)

Structure d'une condition

ParamètreType Valeurs possibles
fieldstringcountry, continent, device, os, browser, language, referrer, social_media, day_of_week, hour, date_range, is_bot, is_first_visit
operatorstringequals, not_equals, contains, not_contains, in, not_in, starts_with, greater_than, less_than, between, not_between
valuestringValeur à comparer (ex: FR, mobile, true)

Exemple de requête

curl -X POST "https://hou.la/api/link/abc123/rules" \
  -H "X-API-Key: houla_sk_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "label": "Visiteurs français mobile",
    "destinationUrl": "https://example.fr/page-fr",
    "matchType": "all",
    "conditions": [
      { "field": "country", "operator": "equals", "value": "FR" },
      { "field": "device", "operator": "equals", "value": "mobile" }
    ]
  }'

A/B Testing avec poids

Pour répartir le trafic entre plusieurs destinations, créez des règles sans conditions mais avec des poids. Le trafic sera distribué proportionnellement aux poids définis.

# Règle A - 70% du trafic
curl -X POST "https://hou.la/api/link/abc123/rules" \
  -H "X-API-Key: houla_sk_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "label": "Variante A",
    "destinationUrl": "https://example.com/page-a",
    "weight": 70,
    "conditions": []
  }'

# Règle B - 30% du trafic
curl -X POST "https://hou.la/api/link/abc123/rules" \
  -H "X-API-Key: houla_sk_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "label": "Variante B",
    "destinationUrl": "https://example.com/page-b",
    "weight": 30,
    "conditions": []
  }'

Modifier une règle

PATCH/link/{linkId}/rules/{ruleId}

Mêmes paramètres que la création. Seuls les champs envoyés sont modifiés.

Supprimer une règle

DELETE/link/{linkId}/rules/{ruleId}

Réordonner les règles

PUT/link/{linkId}/rules/reorder

curl -X PUT "https://hou.la/api/link/abc123/rules/reorder" \
  -H "X-API-Key: houla_sk_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "ruleIds": ["rule-2", "rule-1", "rule-3"]
  }'

11. Webhooks

Les webhooks vous permettent de recevoir des notifications HTTP en temps réel lorsque des événements se produisent sur vos liens ou pages Link-in-Bio. Au lieu de poll l'API régulièrement, configurez un webhook et recevez les données directement sur votre serveur.

Authentification des webhooks : Vérifiez toujours la signature HMAC-SHA256 des requêtes entrantes pour vous assurer qu'elles proviennent bien de Hou.la. Ne traitez jamais un webhook sans vérification.
Exclusivité hou.la :Nous sommes les seuls à proposer les événements profile.visited et profile.link_clicked pour les pages Link-in-Bio.

Événements disponibles

Événement Description
link.clicked Un lien a été cliqué
link.created Un lien a été créé
link.updated Un lien a été modifié
link.deleted Un lien a été supprimé
link.health_changed L'état de santé d'un lien a changé (ex: URL cassée)
link.safety_changed Le statut de sécurité d'un lien a changé
link.expired Un lien éphémère a expiré
link.password_attempt Tentative d'accès à un lien protégé par mot de passe
profile.visited Une page Link-in-Bio a été visitée
profile.link_clicked Un lien a été cliqué sur une page Link-in-Bio

Créer un webhook

POST/manager/webhook

Paramètres

ParamètreTypeRequis Description
namestringOui Nom descriptif (max 100 caractères)
urlstringOui URL de destination (HTTPS requis en production, max 2048 caractères)
eventsstring[]Oui Liste des événements à écouter (au moins 1)
linkIdstringNon UUID du lien spécifique à surveiller
tagIdstringNon UUID du tag pour filtrer les événements
batchSizenumberNon Taille du batch (1-100, défaut: 1 = pas de batching)
batchDelayMsnumberNon Délai max avant envoi du batch en ms (0-60000, défaut: 0)
samplingRatenumberNon Pourcentage d'événements à envoyer (1-100, défaut: 100)
anonymizeIpbooleanNon Anonymiser l'IP dans les payloads (RGPD)
excludeGeoCitybooleanNon Exclure la ville des données de géolocalisation (RGPD)

Exemple de requête

curl -X POST "https://hou.la/api/manager/webhook" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Analytics Integration",
    "url": "https://my-app.com/webhooks/houla",
    "events": ["link.clicked", "link.created"],
    "anonymizeIp": true,
    "excludeGeoCity": true
  }'

Réponse

201 Created

{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "name": "Analytics Integration",
  "url": "https://my-app.com/webhooks/houla",
  "events": ["link.clicked", "link.created"],
  "enabled": true,
  "secret": "whsec_xxxxxxxxxxxxxxxxxxxxxxxx",
  "anonymizeIp": true,
  "excludeGeoCity": true,
  "batchSize": 1,
  "samplingRate": 100,
  "createdAt": "2025-01-15T10:30:00.000Z"
}
Important :Le secret n'est affiché qu'à la création. Conservez-le en lieu sûr pour vérifier les signatures.

Lister les webhooks

GET/manager/webhook

curl -X GET "https://hou.la/api/manager/webhook" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"

Récupérer un webhook

GET/manager/webhook/{id}

curl -X GET "https://hou.la/api/manager/webhook/a1b2c3d4-e5f6-7890-abcd-ef1234567890" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"

Modifier un webhook

PATCH/manager/webhook/{id}

Tous les champs de création sont acceptés en paramètre (sauf secret).

curl -X PATCH "https://hou.la/api/manager/webhook/a1b2c3d4-..." \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Updated Integration",
    "events": ["link.clicked", "link.created", "link.deleted"]
  }'

Supprimer un webhook

DELETE/manager/webhook/{id}

curl -X DELETE "https://hou.la/api/manager/webhook/a1b2c3d4-..." \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"

204 No Content

Activer / Désactiver

POST/manager/webhook/{id}/enable

POST/manager/webhook/{id}/disable

curl -X POST "https://hou.la/api/manager/webhook/a1b2c3d4-.../enable" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"

Tester un webhook

POST/manager/webhook/{id}/test

Envoie un événement de test à l'URL du webhook pour vérifier que votre serveur répond correctement.

curl -X POST "https://hou.la/api/manager/webhook/a1b2c3d4-.../test" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"

Réponse

200 OK

{
  "success": true,
  "statusCode": 200,
  "responseTimeMs": 142
}

Consulter les logs

GET/manager/webhook/{id}/logs

Paramètres query

ParamètreType Description
pagenumber Numéro de page (défaut: 1)
limitnumber Résultats par page (défaut: 20, max: 100)
successbooleanFiltrer par succès (true) ou échec (false)
curl -X GET "https://hou.la/api/manager/webhook/a1b2c3d4-.../logs?page=1&limit=10&success=true" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"

Régénérer le secret

POST/manager/webhook/{id}/regenerate-secret

Génère un nouveau secret de signature. L'ancien secret sera invalidé immédiatement.

curl -X POST "https://hou.la/api/manager/webhook/a1b2c3d4-.../regenerate-secret" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"

Vérification de signature

Chaque requête webhook inclut un en-tête X-Houla-Signature contenant une signature HMAC-SHA256. Vérifiez cette signature pour vous assurer que la requête provient bien de hou.la.

En-têtes envoyés

En-tête Description
X-Houla-Signature Signature HMAC-SHA256 du body
X-Houla-EventType d'événement (ex: link.clicked)
X-Houla-Delivery UUID unique de la livraison
X-Houla-Timestamp Timestamp ISO 8601 de l'envoi

Exemple de vérification (Node.js)

const crypto = require('crypto');

function verifyWebhookSignature(body, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(JSON.stringify(body))
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

// Dans votre handler Express
app.post('/webhooks/houla', (req, res) => {
  const signature = req.headers['x-houla-signature'];
  const event = req.headers['x-houla-event'];

  if (!verifyWebhookSignature(req.body, signature, WEBHOOK_SECRET)) {
    return res.status(401).json({ error: 'Invalid signature' });
  }

  switch (event) {
    case 'link.clicked':
      console.log('Clic sur', req.body.link.shortUrl);
      break;
    case 'profile.visited':
      console.log('Visite page bio', req.body.profile.slug);
      break;
  }

  res.status(200).json({ received: true });
});
Bonnes pratiques : Vérifiez toujours la signature, répondez en moins de 5 secondes (traitez en arrière-plan si nécessaire), et retournez un code 2xx pour confirmer la réception. En cas d'échec, hou.la réessaie automatiquement avec un backoff exponentiel.

12. Pixel Presets

Gérez des presets de pixels de retargeting pour pré-remplir automatiquement vos liens lors de la création.

Lister les presets

GET /api/manager/pixel-preset
Authorization: Bearer <token>

Créer un preset

POST /api/manager/pixel-preset
Authorization: Bearer <token>
Content-Type: application/json

{
  "name": "Mon site e-commerce",
  "isDefault": true,
  "fbPixelId": "123456789012345",
  "googleTagId": "G-AB1CDE2FGH"
}
ParamètreTypeRequis Description
namestringOui Nom du preset (1-100 caractères)
isDefaultbooleanNon Définir comme preset par défaut pour les nouveaux liens
fbPixelIdstringNon Facebook Pixel ID (10-20 chiffres)
googleTagIdstringNon Google Tag ID (G-XXX, AW-XXX, DC-XXX ou UA-XXX)
tiktokPixelIdstringNon TikTok Pixel ID (commence par C, 11-31 caractères)

Modifier un preset

PATCH /api/manager/pixel-preset/:id
Authorization: Bearer <token>

Supprimer un preset

DELETE /api/manager/pixel-preset/:id
Authorization: Bearer <token>

13. Domaines personnalisés

Ajoutez vos propres domaines pour personnaliser vos liens courts. Cette fonctionnalité est réservée aux plans payants.

Plan requis : Les domaines personnalisés sont disponibles à partir du plan Pro.

Ajouter un domaine

POST/domains

Ajoute un domaine personnalisé à votre compte. Vous devrez configurer un enregistrement DNS pour vérifier la propriété du domaine.

ParamètreTypeRequis Description
domainstringOui Le nom de domaine à ajouter (ex : links.monsite.com)
curl -X POST "https://hou.la/api/domains" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "domain": "links.monsite.com"
  }'

Réponse

201 Created

{
  "id": "a1b2c3d4-...",
  "domain": "links.monsite.com",
  "status": "pending",
  "verificationMethod": "cname",
  "verificationToken": "houla-verify-abc123...",
  "dnsVerified": false,
  "sslConfigured": false,
  "isActive": false,
  "cnameTarget": "custom.hou.la",
  "txtRecordName": "_houla-verify.links.monsite.com",
  "createdAt": "2025-01-15T10:30:00.000Z",
  "updatedAt": "2025-01-15T10:30:00.000Z"
}

Lister les domaines

GET/domains

curl -X GET "https://hou.la/api/domains" \
  -H "Authorization: Bearer <token>"

Réponse

200 OK

[
  {
    "id": "a1b2c3d4-...",
    "domain": "links.monsite.com",
    "status": "active",
    "verificationMethod": "cname",
    "dnsVerified": true,
    "sslConfigured": false,
    "isActive": true,
    "cnameTarget": "custom.hou.la",
    "txtRecordName": "_houla-verify.links.monsite.com",
    "createdAt": "2025-01-15T10:30:00.000Z",
    "updatedAt": "2025-01-15T12:00:00.000Z"
  }
]

Récupérer un domaine

GET/domains/{id}

curl -X GET "https://hou.la/api/domains/a1b2c3d4-..." \
  -H "Authorization: Bearer <token>"

Vérifier un domaine

POST/domains/{id}/verify

Déclenche la vérification DNS du domaine. Le système vérifie que l’enregistrement CNAME ou TXT est correctement configuré.

curl -X POST "https://hou.la/api/domains/a1b2c3d4-.../verify" \
  -H "Authorization: Bearer <token>"

Réponse

200 OK — Domaine vérifié avec succès

{
  "id": "a1b2c3d4-...",
  "domain": "links.monsite.com",
  "status": "active",
  "dnsVerified": true,
  "dnsVerifiedAt": "2025-01-15T12:00:00.000Z",
  "isActive": true
}

Changer la méthode de vérification

PATCH/domains/{id}/verification-method

Change la méthode de vérification DNS du domaine (CNAME ou TXT).

ParamètreTypeRequis Description
methodstringOui Méthode de vérification : « cname » ou « txt »
curl -X PATCH "https://hou.la/api/domains/a1b2c3d4-.../verification-method" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "method": "txt"
  }'

Supprimer un domaine

DELETE/domains/{id}

curl -X DELETE "https://hou.la/api/domains/a1b2c3d4-..." \
  -H "Authorization: Bearer <token>"

200 OK

{
  "success": true
}

Configuration DNS

Selon la méthode de vérification choisie, configurez l’un des enregistrements DNS suivants :

Méthode CNAME (recommandée)

links.monsite.com.  CNAME  custom.hou.la.

Méthode TXT

_houla-verify.links.monsite.com.  TXT  "houla-verify-abc123..."
Statuts possibles : pending (en attente de vérification), active (vérifié et actif), failed (échec de vérification).

Vendez des produits physiques, digitaux, services ou acceptez des dons directement depuis vos pages Link in Bio. Les paiements sont traités via Stripe Connect.

Un compte Stripe Connect actif est requis pour créer des Pay Links. Lancez l’onboarding depuis le dashboard manager.

Onboarding Stripe Connect

POST/manager/stripe-connect/onboard

Lance le processus d’onboarding Stripe Connect Express. Retourne une URL de redirection vers le formulaire Stripe.

Réponse

201 Created

{
  "url": "https://connect.stripe.com/setup/s/..."
}

Statut Stripe Connect

GET/manager/stripe-connect/status

Retourne le statut actuel du compte Stripe Connect du vendeur.

Réponse

200 OK

{
  "status": "active",
  "chargesEnabled": true,
  "payoutsEnabled": true,
  "detailsSubmitted": true
}

Lister les Pay Links

GET/manager/bio-pages/{bioPageId}/pay-links

Retourne tous les Pay Links d’une page Bio, triés par ordre d’affichage.

Réponse

200 OK

[
  {
    "id": "uuid",
    "title": "E-book SEO Pro",
    "productType": "digital",
    "priceInCents": 1999,
    "currency": "EUR",
    "status": "active",
    "quantitySold": 42,
    "quantityAvailable": 58,
    "displayOrder": 0
  }
]

Créer un Pay Link

POST/manager/bio-pages/{bioPageId}/pay-links

Crée un nouveau Pay Link sur une page Bio. Le vendeur doit avoir un compte Stripe Connect actif.

Paramètres

ParamètreTypeRequis Description
titlestringOui Titre du produit (max 120 caractères)
priceInCentsintegerOui Prix en centimes (ex : 1999 = 19,99 €)
descriptionstringNon Description du produit
imageUrlstringNon URL de l’image du produit
productTypestringNon Type de produit : physical, digital, service, donation (défaut : physical)
currencystringNon Devise : EUR, USD, GBP, CAD, CHF (défaut : EUR)
compareAtPriceintegerNon Prix barré en centimes (prix avant promo)
quantityAvailableintegerNon Stock disponible (null = illimité)
maxPerOrderintegerNon Quantité maximum par commande (1-100, défaut : 1)
shippingCostintegerNon Frais de livraison en centimes
shippingCountriesstring[]Non Codes ISO pays de livraison (ex : ["FR", "BE", "CH"])
digitalFileUrlstringNon URL du fichier à télécharger (produits digitaux)
digitalFileNamestringNon Nom du fichier affiché à l’acheteur
ctaStylestringNon Style du CTA : default, featured, minimal
ctaTextstringNon Texte du bouton d’achat (max 40 caractères)

Exemple de requête

curl -X POST "https://hou.la/api/manager/bio-pages/BIO_ID/pay-links" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "E-book SEO Pro",
    "priceInCents": 1999,
    "currency": "EUR",
    "productType": "digital",
    "digitalFileUrl": "https://storage.example.com/ebook.pdf",
    "digitalFileName": "ebook-seo-pro.pdf",
    "maxPerOrder": 1
  }'

Réponse

201 Created

Modifier un Pay Link

PATCH/manager/pay-links/{id}

Modifie un Pay Link existant. Seuls les champs envoyés sont mis à jour.

Accepte les mêmes paramètres que la création, plus le champ status (active, paused, sold_out, archived).

Estimer la livraison d'un panier

POST/bio/{username}/shop/shipping-estimate

Calcule les frais de livraison d'un panier et retourne une fenêtre de livraison estimée tenant compte du délai de préparation vendeur, des vacances vendeur, du pays d'expédition et d'un éventuel panier ouvert déjà fusionné.

Paramètres

ParamètreTypeRequis Description
itemsarrayOui Lignes du panier. Chaque entrée contient au minimum productId et quantity.
buyerCountrystringNon Code ISO du pays acheteur. Si omis, l'API tente une détection GeoIP puis retombe sur FR.
buyerEmailstringNon Email acheteur pour détecter un panier ouvert existant et recalculer uniquement le complément de livraison.

Exemple de requête

curl -X POST "https://hou.la/api/bio/testshop/shop/shipping-estimate" \
    -H "Content-Type: application/json" \
    -d '{
        "items": [
            { "productId": "PRODUCT_ID", "quantity": 2 }
        ],
        "buyerCountry": "FR",
        "buyerEmail": "client@example.com"
    }'

Réponse

200 OK

La réponse inclut les frais de livraison recalculés, l'état du retrait sur place, et un objet deliveryEstimate avec la fenêtre estimée, le transporteur générique appliqué et l'impact éventuel des vacances vendeur.

{
    "shippingCents": 590,
    "freeShipping": false,
    "buyerCountry": "FR",
    "mergeDetected": false,
    "localPickupAvailable": true,
    "localPickupInstructions": "Retrait du lundi au vendredi, 9h-18h",
    "deliveryEstimate": {
        "carrierName": "Hou.la Standard",
        "carrierServiceName": "Local / National Standard",
        "minDeliveryDate": "2026-03-24",
        "maxDeliveryDate": "2026-03-27",
        "minDeliveryLabel": "24 mars 2026",
        "maxDeliveryLabel": "27 mars 2026",
        "sellerVacationApplied": false,
        "cartCloseDate": "2026-03-24"
    }
}

Supprimer un Pay Link

DELETE/manager/pay-links/{id}

Supprime un Pay Link (soft delete). Les commandes existantes sont conservées.

Réponse

204 No Content

Lister les commandes

GET/manager/pay-orders

Retourne les commandes du vendeur avec pagination et filtres.

ParamètreTypeRequis Description
pageintegerNon Numéro de page (défaut : 1)
limitintegerNon Nombre de résultats par page (max 100, défaut : 20)
statusstringNon Filtrer par statut : pending, paid, processing, fulfilled, failed, refunded, partially_refunded
payLinkIdstringNon Filtrer par PayLink ID
dateFromstringNon Date de début (ISO 8601)
dateTostringNon Date de fin (ISO 8601)

Statistiques des ventes

GET/manager/pay-orders/stats

Retourne un résumé des ventes : chiffre d’affaires total, nombre de commandes, remboursements, et données du mois en cours.

Réponse

200 OK

{
  "totalRevenue": 150000,
  "totalOrders": 75,
  "totalRefunded": 2,
  "thisMonthRevenue": 32000,
  "thisMonthOrders": 12
}

Rembourser une commande

POST/manager/pay-orders/{id}/refund

Rembourse une commande via Stripe. Par défaut, remboursement total. Spécifiez amountCents pour un remboursement partiel.

ParamètreTypeRequis Description
amountCentsintegerNon Montant à rembourser en centimes (omis = remboursement total)
reasonstringNon Motif du remboursement

15. Import de liens (Bitly)

Importez vos liens depuis Bitly vers Hou.la. L'import est asynchrone : vous lancez un job et suivez sa progression via SSE ou polling.

L'import de liens nécessite un plan Pro (1 000 liens max) ou Business (10 000 liens max). Les comptes gratuits ne peuvent pas utiliser cette fonctionnalité.

Lancer un import

Démarre un job d'import asynchrone depuis la source spécifiée. Retourne un objet ImportJob avec un identifiant pour suivre la progression.

POST /api/manager/import/start
Authorization: Bearer JWT_TOKEN
X-Workspace-Id: WORKSPACE_ID
Content-Type: application/json
PAGES.API_DOC.TH_PARAMETERTypeRequis Description
sourcestringOui Source de l'import (actuellement : "bitly")
apiTokenstringOui Token d'accès API de la source (Bitly Generic Access Token)
skipDuplicatesbooleanNon Ignorer les liens déjà importés (défaut : true)
preserveTagsbooleanNon Conserver les tags Bitly en tant que tags Hou.la (défaut : false)
preserveCustomSlugsbooleanNon Tenter de conserver les slugs personnalisés Bitly (défaut : false)

Limites par plan

Plan Liens max par import
Free Non disponible
Pro1 000
Business10 000

Exemple

curl -X POST https://api.hou.la/api/manager/import/start \
  -H "Authorization: Bearer $JWT_TOKEN" \
  -H "X-Workspace-Id: $WORKSPACE_ID" \
  -H "Content-Type: application/json" \
  -d '{"source":"bitly","apiToken":"YOUR_BITLY_TOKEN","skipDuplicates":true}'

Lister les imports

Retourne la liste de tous les jobs d'import de l'utilisateur, triés du plus récent au plus ancien.

GET /api/manager/import
Authorization: Bearer JWT_TOKEN
X-Workspace-Id: WORKSPACE_ID

Détail d'un import

Retourne les détails d'un job d'import spécifique, incluant le statut, la progression et les éventuelles erreurs.

GET /api/manager/import/:id
Authorization: Bearer JWT_TOKEN
X-Workspace-Id: WORKSPACE_ID

Annuler un import

Annule un job d'import en cours. Seuls les imports au statut "pending" ou "running" peuvent être annulés.

POST /api/manager/import/:id/cancel
Authorization: Bearer JWT_TOKEN
X-Workspace-Id: WORKSPACE_ID

Suivre la progression (SSE)

Flux Server-Sent Events (SSE) pour suivre la progression de l'import en temps réel. Émet des événements progress, completed ou failed.

GET /api/manager/import/:id/progress
Authorization: Bearer JWT_TOKEN
X-Workspace-Id: WORKSPACE_ID

14. Codes d’erreur

Code Description
400Requête invalide - Vérifiez les paramètres envoyés
401Non autorisé - Clé API manquante ou invalide
403Interdit - Clé API révoquée ou accès refusé
404Non trouvé - La ressource demandée n'existe pas
429Trop de requêtes - Limite de débit atteinte ou protection de sécurité activée
500Erreur serveur - Contactez le support

15. Limites de requêtes (Rate Limiting)

L'API applique des limites de requêtes selon le type d'authentification utilisé :

Type d'utilisateur LimiteTTL
Anonyme 10 req/min60s
JWT authentifié100 req/min60s
Clé API1000 req/min60s
Login / Auth5 req/min60s
Les requêtes GET de lecture (récupération, liste) ne sont pas soumises au rate limiting.
En-têtes de rate limit :Chaque réponse inclut les en-têtes X-RateLimit-Limit, X-RateLimit-Remaining et X-RateLimit-Reset pour vous permettre de gérer vos quotas.
429 Too Many Requests : Si vous dépassez ces limites, l'API retournera une erreur 429. Attendez la fin du TTL avant de réessayer.
Sécurité renforcée : Les liens protégés par mot de passe bénéficient d'une protection supplémentaire. Cette protection est indépendante du rate limiting général.

16. Bonnes pratiques

Pour une utilisation optimale de l'API, nous recommandons de :

  • Conserver votre clé API en sécurité et ne jamais la partager publiquement
  • Utiliser des variables d'environnement pour stocker vos clés
  • Éviter de créer des requêtes en boucle trop rapides
  • Gérer les erreurs et implémenter une logique de retry avec backoff

17. SDK officiel (NPM)

Le SDK houla-sdk vous permet d'intégrer rapidement l'API Hou.la dans vos projets Node.js/TypeScript.

Installation

npm install @houla/sdk

Utilisation

import { HoulaClient } from '@houla/sdk';

const client = new HoulaClient('houla_sk_xxxxxxxx');

// Créer un lien
const link = await client.createLink({
  url: 'https://example.com/ma-page',
  title: 'Mon lien'
});

console.log(link.shortUrl); // https://hou.la/xY7k9

// Créer un lien protégé par mot de passe
const protectedLink = await client.createLink({
  url: 'https://example.com/secret',
  title: 'Document confidentiel',
  password: 'secret123'
});

// Lister les liens
const result = await client.getLinks({ page: 1, limit: 10 });

// Récupérer un lien par ID
const details = await client.getLinkById('abc123');

// Supprimer un lien
await client.deleteLink('abc123');

// ─── Webhooks ───

// Créer un webhook
const webhook = await client.createWebhook({
  name: 'Mon webhook',
  url: 'https://my-app.com/webhooks/houla',
  events: ['link.clicked', 'link.created'],
  anonymizeIp: true
});
console.log(webhook.secret); // À conserver !

// Lister les webhooks
const webhooks = await client.getWebhooks();

// Tester un webhook
const test = await client.testWebhook(webhook.id);
console.log(test.success, test.responseTimeMs);

// Consulter les logs
const logs = await client.getWebhookLogs(webhook.id, 1, 20);
Documentation :Consultez le README du SDK pour la liste complète des méthodes disponibles.

19. Impression automatique (Desktop App)

L'API Print permet au client desktop Hou.la Print de recevoir et gérer les jobs d'impression en temps réel. Les endpoints de la section /api/print utilisent l'authentification par clé API (header X-API-Key).

Ces endpoints sont destinés au client desktop Hou.la Print. Ils sont authentifiés par clé API (X-API-Key), pas par JWT.

Configuration d'impression

GET/api/print/config

Récupère la configuration d'impression du workspace courant.

PATCH/api/manager/print/config

Met à jour la configuration d'impression (endpoint manager, authentification JWT).

Paramètres

ParamètreType Description
enabledboolean Activer/désactiver l'impression automatique
autoProductLabelsboolean Impression automatique des étiquettes produits
autoOrderSummaryboolean Impression automatique du récapitulatif commande
autoInvoiceboolean Impression automatique des factures
autoInvoiceTrigger"paid" | "processing" Déclencheur de la facture : 'paid' (paiement reçu) ou 'processing' (commande en cours)
autoShippingLabelboolean Impression automatique des étiquettes d'expédition
autoPackingSlipboolean Impression automatique des bordereaux de livraison
productLabelTemplate"standard" | "minimal" | "detailed" Style du template d'étiquette : standard, minimal ou detailed
brandNamestring Nom de marque affiché sur les étiquettes (max 100 caractères)

Jobs d'impression

GET/api/print/jobs?status=pending

Liste les jobs d'impression du workspace, filtrables par statut et type.

Paramètres de requête

ParamètreType Description
statusstring Filtrer par statut : pending, sent, printed, failed, cancelled
typestring Filtrer par type : product_label, order_summary, invoice, shipping_label, packing_slip
limitnumber Nombre maximum de résultats (1-100, défaut : 50)
offsetnumber Offset pour la pagination (défaut : 0)

Acquitter un job

POST/api/print/jobs/{id}/ack

Confirme qu'un job a été imprimé avec succès ou a échoué.

ParamètreTypeRequis Description
status"printed" | "failed"Oui Statut final du job : 'printed' (succès) ou 'failed' (échec)
errorstringNon Message d'erreur (si status=failed, max 1000 caractères)

Exemple de requête

curl -X POST "https://hou.la/api/print/jobs/{jobId}/ack" \
  -H "X-API-Key: houla_sk_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "printed"
  }'

Télécharger le contenu d'une étiquette

GET/api/print/jobs/{id}/label

Retourne le contenu de l'étiquette (ZPL, ESC/POS inline) ou l'URL de téléchargement (PDF, PNG).

Réponse

{
  "id": "abc-123",
  "type": "product_label",
  "labelFormat": "zpl",
  "labelData": "^XA^FO50,50^A0N,40,40^FDMon Produit^FS^XZ",
  "labelUrl": null
}

20. Support

Pour toute question concernant l'API, contactez-nous à : hello@hou.la

Vous pouvez également consulter notre page de support pour plus d'informations.