Linear est passé en Live dans le catalogue d'intégrations Elido le 22-05-2026. Le premier événement que nous avons livré était broken_link_hook - quand notre scanner trouve un lien court mort, il crée un issue Linear dans l'équipe que vous avez choisie à la connexion, avec des métriques de clics dans le corps et des labels routés par tag. Ce billet est le guide technique de l'ingénieur : comment fonctionne l'authentification, à quoi ressemble le payload JSON, et comment nous avons étendu la même pipeline aux pics de seuil de clics pour que l'astreinte reçoive un ticket plutôt qu'une alerte à 3h du matin.
Si vous maintenez des centaines ou des milliers de liens courts en production, vous connaissez déjà le mode de défaillance. Le marketing change la destination d'une campagne, la nouvelle URL retourne 404, et personne ne le remarque avant qu'un client partage une capture d'écran du lien mort sur Bluesky. Linear est l'endroit où votre équipe triage déjà les bugs, c'est donc là qu'on met le ticket.
Connecter Linear via Personal API Key
L'intégration Linear utilise une Personal API Key, pas OAuth. Nous avons fait ce choix pour trois raisons : les API Keys sont limitées au workspace, elles survivent mieux aux changements d'administrateur que les tokens OAuth liés à un seul utilisateur, et la documentation API: Authentication de Linear les recommande explicitement pour les jobs serveur à serveur.
Générez la clé dans Linear : Paramètres, API, Personal API keys, Créer une clé. Nommez-la elido-integration pour pouvoir la révoquer plus tard sans se poser de questions. Copiez la clé (elle commence par lin_api_) et collez-la dans la carte d'intégration Linear sur le tableau de bord Elido.
Ce qui se passe ensuite : nous effectuons une requête viewer pour valider la clé, puis une requête teams pour remplir le sélecteur d'équipe. Vous choisissez une équipe par défaut. Ce choix écrit une ligne dans integration_configs dans Postgres, incluant le team ID attribué par Linear. Si vous avez plusieurs équipes, vous pouvez ajouter un routage par tag sur le même écran - plus de détails ci-dessous.
POST /v1/workspaces/:id/integrations/linear/connect
{
"api_key": "lin_api_<redacted>",
"default_team_id": "TEAM_a1b2c3",
"default_priority": 2,
"labels": ["short-link", "auto-filed"]
}
En coulisses, le service api-core stocke la clé chiffrée au repos via le schéma de chiffrement par enveloppe de l'ADR-0036. La clé déchiffrée ne vit en mémoire que pendant l'appel GraphQL réel. Nous ne logguons jamais la valeur brute, et l'interface des logs d'intégration n'affiche que les 4 derniers caractères.
Un point important : les Personal API Keys de Linear sont liées à l'utilisateur qui les a créées. Si cet utilisateur quitte votre entreprise et que vous désactivez son compte Linear, la clé meurt avec lui. La bonne pratique est de créer un utilisateur de type service dans Linear (nous utilisons [email protected]) et de générer la clé depuis ce compte.
L'événement broken_link_hook - ce qui le déclenche et ce qu'il contient
Notre service url-scanner effectue un crawl hebdomadaire de tous les liens courts actifs dans votre workspace. Pour chaque lien, il envoie un HTTP HEAD vers la destination, puis un GET si HEAD n'est pas supporté, puis valide la chaîne TLS. Quatre conditions déclenchent l'état lien brisé :
- HTTP 4xx ou 5xx sur deux sondages consécutifs (double vérification pour absorber les 500 transitoires)
- TLS expiré ou auto-signé alors qu'il était valide la semaine précédente
- DNS NXDOMAIN - l'hôte de destination ne résout plus
- Correspondance d'empreinte de domaine parqué - la destination résout mais le corps de la réponse correspond à un modèle de squatter connu (nous maintenons un petit ensemble d'empreintes)
Quand l'une de ces quatre conditions est atteinte, le scanner publie un événement link.broken dans Redpanda. Le webhook-dispatcher le consomme, recherche vos intégrations actives et pour Linear matérialise le payload ci-dessous.
Voici un vrai payload broken_link_hook capturé depuis notre environnement de staging (certains champs omis) :
{
"event": "link.broken",
"link_id": "01J9V7QXMZ8K2Y3N4P5R6T7W8Z",
"short_url": "https://s.elido.me/spring-launch",
"destination_url": "https://oldcampaign.example.com/landing",
"failure_type": "http_5xx",
"failure_detail": "502 Bad Gateway, 2 consecutive probes",
"last_working_at": "2026-05-28T14:22:00Z",
"detected_at": "2026-06-04T03:11:42Z",
"clicks_last_7d": 2841,
"clicks_last_24h": 412,
"top_referrers": [
{ "host": "linkedin.com", "clicks": 1203 },
{ "host": "twitter.com", "clicks": 488 },
{ "host": "direct", "clicks": 612 }
],
"tags": ["campaign-spring-2026", "paid"],
"owner_email": "[email protected]"
}
L'adaptateur Linear dans services/api-core/internal/integrations/linear/broken_link_hook.go prend ce payload et construit une mutation GraphQL contre l'Issues API de Linear. Le titre de l'issue suit un modèle fixe pour que l'astreinte puisse le trouver avec grep :
[Elido] Broken link: /spring-launch (502 Bad Gateway)
Le corps est du Markdown structuré en cinq sections : détails du lien, dernier horodatage fonctionnel, delta de clics par rapport à la baseline sur 7 jours, les trois principaux referrers et un bloc de correction suggérée. Le bloc de correction examine failure_type et choisit une suggestion prédéfinie - pour http_5xx, "Vérifiez si la destination applique un rate limit ou est en cours de déploiement" ; pour parked_domain, "Le domaine a peut-être expiré ou été squatté, archivez ce lien" ; et ainsi de suite.
Les labels sont attribués depuis deux sources : votre ensemble de labels par défaut (configuré à la connexion) et des labels dynamiques dérivés de la liste de tags. Si un tag correspond à paid ou organic, nous l'ajoutons comme label pour que les PMs puissent filtrer leurs vues Linear.
Déduplication, rate limits et dead-letter queue
Nous dédupliclons les événements broken_link_hook par hôte de destination pendant 24 heures. Si oldcampaign.example.com est mort et que 800 liens courts y pointent, vous recevez un seul ticket Linear avec les 800 URLs courtes listées dans le corps, pas 800 tickets séparés. Ce fut une leçon difficile lors de la bêta précoce - le premier client à toucher un domaine mort a été submergé.
L'endpoint GraphQL de Linear a un rate limit global par workspace. Notre webhook-dispatcher suit le header Retry-After et utilise un backoff exponentiel avec full jitter, jusqu'à cinq tentatives. Après cinq, l'événement atterrit dans une dead-letter queue. Vous pouvez voir les entrées DLQ dans Paramètres, Intégrations, Linear, Événements échoués, et rejouer n'importe lequel en un clic. La DLQ est également exposée via la fonctionnalité webhooks pour un replay programmatique.
Seuil de clics et déclencheurs personnalisés
Le même adaptateur Linear consomme les événements click_threshold_hook. Vous définissez des seuils par lien ou par campagne dans le tableau de bord Elido, et nous créons un issue Linear quand un lien franchit une bande. Deux types de bandes sont supportés aujourd'hui :
- Spike : les clics de la dernière heure dépassent N fois la baseline horaire glissante sur 7 jours (N par défaut est 3). Utile pour détecter la viralité ou, moins agréablement, le trafic de bots.
- Cliff : les clics de la dernière heure tombent sous 10% de la baseline glissante. Utile pour détecter les campagnes mortes - si une publicité payante a été mise en pause en amont, vous voyez le ticket Linear avant le standup marketing.
Voici un payload click_threshold_hook :
{
"event": "link.click_threshold",
"link_id": "01J9V7QXMZ8K2Y3N4P5R6T7W8Z",
"short_url": "https://s.elido.me/spring-launch",
"band": "spike",
"current_hour_clicks": 8421,
"baseline_hourly_clicks": 612,
"multiplier": 13.76,
"top_referrers": [
{ "host": "news.ycombinator.com", "clicks": 6203 },
{ "host": "direct", "clicks": 1488 }
],
"tags": ["campaign-spring-2026"],
"triggered_at": "2026-06-04T11:14:00Z"
}
Pour un spike, le bloc de correction indique : "Vérifiez s'il s'agit de trafic organique et non d'une campagne de spoofing de referrers. Consultez la répartition des referrers ci-dessus." Pour un cliff : "Confirmez que la campagne est toujours active en amont. Si elle a été mise en pause, archivez ce lien."
Routage par tag entre plusieurs équipes
Le sélecteur d'équipe par défaut convient pour un workspace de 20 personnes. Pour les organisations plus importantes, vous voulez qu'un ticket Linear sur un lien marketing aille à l'équipe Marketing, et qu'un ticket sur un lien docs aille à l'équipe Documentation. Le routage par tag gère ça.
Les règles de routage vivent dans integration_configs.routing_json et sont évaluées de haut en bas. Une règle ressemble à :
[
{
"tag_glob": "campaign-*",
"team_id": "TEAM_growth",
"labels": ["growth", "urgent"]
},
{ "tag_glob": "docs-*", "team_id": "TEAM_docs", "labels": ["docs"] },
{
"tag_glob": "internal-*",
"team_id": "TEAM_internal",
"labels": ["internal"]
},
{ "default": true, "team_id": "TEAM_a1b2c3" }
]
La première règle dont le glob correspond à au moins un tag du lien gagne. Si rien ne correspond, la règle par défaut prend l'événement. La syntaxe glob est la même que les filtres de vues sauvegardées de Linear, que les PMs connaissent déjà.
Vous pouvez également router par failure_type. Certaines équipes veulent que tous les échecs TLS aillent à l'équipe plateforme car ils indiquent généralement une mauvaise configuration de certificat sur un domaine personnalisé de tenant. Ajoutez une règle avec failure_type: tls_expired et c'est fait.
Déclencheurs personnalisés via webhooks
Toutes les équipes ne souhaitent pas créer des tickets Linear pour chaque type d'événement que nous publions. Le catalogue complet des événements est documenté sur la page de la fonctionnalité webhooks, mais les associations courantes que les équipes configurent aux côtés de Linear sont :
link.createdvers une équipe Linear pour les audits de nouveaux liens (rare, généralement pour les équipes de conformité)domain.takeover_detectedpour les surprises TLS sur les domaines personnaliséslink.scan_completepour les tickets de résumé hebdomadaire (un issue par exécution de scan, listant tous les liens signalés)
Si l'événement dont vous avez besoin n'est pas dans le catalogue, vous pouvez créer le vôtre en utilisant la cible webhook générique et notre guide d'observabilité. Ou soumettez simplement une demande de fonctionnalité sur notre tableau Linear public - méta mais récursif.
Tarification et ce que vous obtenez selon le plan
L'intégration Linear est incluse dans le tier Pro et au-dessus. Sur Free, vous pouvez connecter Linear mais n'obtenez que broken_link_hook (pas de seuil de clics ni de déclencheurs personnalisés). Consultez la page de tarification pour la matrice complète. Si vous êtes une grande équipe qui envisage cela pour des raisons de conformité - par exemple, l'article 32 du RGPD vous demande de détecter les fuites de données via des redirections brisées pointant vers des domaines squattés - la page des solutions Enterprise couvre ce que nous proposons à grande échelle.
Lectures connexes
- Webhooks pour les événements de lien : guide du développeur - le bus d'événements sous-jacent qui alimente toutes les intégrations, y compris Linear.
- Câblage de Sentry sur 12 services Go - comment nous surveillons le dispatcher qui déclenche les événements Linear, pour savoir quand le dispatcher lui-même est défaillant.
- Stratégie de prévention du link rotting - l'histoire opérationnelle plus large derrière la raison pour laquelle nous avons construit la détection de liens brisés.
Le catalogue d'intégrations complet liste 43 fournisseurs en juin 2026, avec Linear parmi les 20 actifs. Si votre équipe utilise Jira à la place, cet adaptateur est en bêta - envoyez-nous un email et nous vous activons.
Questions fréquentes
Comment Elido s'authentifie-t-il auprès de Linear ?
Nous utilisons une Personal API Key limitée au workspace, pas OAuth. Vous générez la clé dans Linear sous Paramètres, API, puis vous la collez dans la carte d'intégration Elido. La clé ne quitte jamais notre vault, et nous la masquons dans les logs. Si vous la faites tourner, le prochain événement déclenche une invite de réauthentification douce au lieu d'échouer silencieusement.
Qu'est-ce qui compte exactement comme lien brisé dans l'événement broken_link_hook ?
Notre url-scanner crawle chaque lien court actif chaque semaine et signale quatre conditions : HTTP 4xx ou 5xx sur deux sondages consécutifs, certificat TLS expiré ou non vérifiable, DNS NXDOMAIN, et empreintes de domaines parqués connus. L'une de ces quatre conditions crée un unique issue Linear, dédupliqué par hôte de destination pendant 24 heures pour qu'un domaine mort ne génère pas 800 tickets.
Puis-je envoyer des issues à différentes équipes Linear selon les tags du lien ?
Oui. Sur l'écran de connexion, vous choisissez une équipe par défaut, puis vous ajoutez des règles de routage - par exemple, les tags correspondant à campaign-* vont à l'équipe Growth, tandis que les tags correspondant à docs-* vont à Ingénierie. Les règles sont évaluées de haut en bas avec un fallback par défaut. Le jeu de règles vit dans Postgres, vous pouvez donc auditer les changements via la piste d'administration.
Est-ce que ça fonctionne aussi pour les alertes de seuil de clics, pas seulement les liens brisés ?
Oui, depuis la Phase 12. Le même adaptateur Linear consomme les événements click_threshold_hook aux côtés de broken_link_hook. Vous définissez des seuils par lien ou par campagne dans le tableau de bord Elido, et nous créons un issue Linear quand un lien franchit une bande - soit un pic (3x la baseline en une heure) soit une falaise (chute sous 10% de la baseline).
Que se passe-t-il si Linear applique un rate limit à l'intégration ?
L'endpoint GraphQL de Linear renvoie un 429 avec un header Retry-After. Notre webhook-dispatcher le respecte avec un backoff exponentiel jusqu'à cinq tentatives, puis place l'événement dans une dead-letter queue. Vous pouvez consulter les entrées DLQ dans Paramètres, Intégrations, Linear, Événements échoués, et les rejouer en un clic. La DLQ est également accessible via la GraphQL API à /v1/integrations/linear/dlq. Nous n'avons pas encore vu de 429 soutenu de Linear en production.
Essayer Elido
Collez une URL, obtenez un lien court
Sans inscription. Lien actif 30 jours. Inscrivez-vous pour le garder pour toujours.
Gratuit, sans inscription · 2 par jour