---
title: "Construire une intégration Shopify Flow : déclencheurs, actions et les pièges qui nous ont coûté un cycle"
description: "Les clés de champ des déclencheurs et des actions suivent des casses opposées, et tout champ de déclencheur est obligatoire : deux pièges coûteux."
url: "https://www.quotway.com/fr/blog/building-a-shopify-flow-integration"
type: "blog post"
category: "Engineering"
published: "2026-07-04"
updated: "2026-10-07"
verified: "2026-10-07"
shopify_api_version: "2026-10"
audience: "Développeurs d'applications Shopify qui construisent des déclencheurs, actions et modèles Flow"
scope: "Une intégration Flow en API 2026-10 : les extensions déclencheur, action et modèle, les conventions de casse opposées, le contrat « tous les champs obligatoires », et les pièges de déploiement et de débogage venus de notre propre construction"
locale: "fr"
source: "QuotWay - B2B Quote & Negotiation App for Shopify"
---

# Construire une intégration Shopify Flow : déclencheurs, actions et les pièges qui nous ont coûté un cycle

**En bref :** une intégration Shopify Flow comporte trois éléments mobiles - les **déclencheurs** (les événements que votre application émet vers Flow), les **actions** (les étapes que Flow rappelle dans votre application) et les **modèles** (des workflows prêts à l'emploi). Les fichiers de configuration des extensions sont du TOML simple ; les pièges se trouvent dans les règles non documentées de la plateforme. Les deux qui nous ont coûté une vraie séance de débogage : **les clés de champ des déclencheurs et celles des actions suivent des conventions de casse opposées**, et **chaque champ déclaré sur un déclencheur est obligatoire dans chaque charge utile** - un « champ de référence facultatif » est donc une contradiction qui casse silencieusement les événements sans compte. Voici la carte complète, après avoir livré 10 déclencheurs, 3 actions et 6 modèles dans [QuotWay](/features/shopify-flow).

## Ce qu'est une intégration Flow (et qui peut s'en servir)

[Shopify Flow](https://shopify.dev/docs/apps/build/flow) est le constructeur d'automatisations sans code de Shopify. Votre application s'y branche de trois façons :

- **Les déclencheurs** (`flow_trigger`) - votre application émet un événement (« devis envoyé »), et les marchands construisent des workflows qui en partent.
- **Les actions** (`flow_action`) - un workflow Flow appelle votre application pour *faire* quelque chose (« mettre à jour le statut d'un devis »), en transmettant les champs configurés par le marchand.
- **Les modèles** (`flow_template`) - des workflows préconstruits qui apparaissent dans la galerie de modèles de Flow, pour que les marchands partent d'un exemple qui marche plutôt que d'une page blanche.

Un mythe à tuer d'emblée : **Flow n'est pas réservé à Plus pour les extensions fournies par des applications.** Les déclencheurs et actions Flow d'une application publique de l'App Store sont disponibles pour les marchands de **n'importe quel forfait Shopify payant**, pas seulement Plus. (Les workflows Flow créés par les marchands ont leurs propres règles de forfait, mais c'est un sujet distinct de la *disponibilité* de vos extensions.) Nous limitons les nôtres par choix de packaging - déclencheurs sur notre niveau Professional, actions sur Enterprise - et non parce que la plateforme l'impose.

## L'anatomie en trois parties

Chaque déclencheur, action et modèle est son propre répertoire d'extension, avec un `shopify.extension.toml`. Il n'existe pas d'objet « application Flow » partagé : vous composez l'intégration à partir de nombreuses petites extensions.

### Les déclencheurs : votre application → Flow

Un déclencheur déclare un nom et un ensemble de champs qui deviennent les données disponibles dans le workflow. Les clés de champ sont le **contrat public de la charge utile** :

```toml
# extensions/flow-quote-submitted/shopify.extension.toml
[[extensions]]
type = "flow_trigger"
name = "Quote submitted"
handle = "quote-submitted"

  [[settings.fields]]
  type = "single_line_text_field"
  key = "Quote id"            # ← Casse de titre, avec espaces

  [[settings.fields]]
  type = "number_decimal"
  key = "Total amount"        # les marchands ajoutent des conditions « Total amount >= X »

  [[settings.fields]]
  type = "single_line_text_field"
  key = "Customer id"         # chaîne VIDE pour les visiteurs sans compte - voir le piège n° 2
```

Vous émettez un événement en appelant la mutation `flowTriggerReceive` avec le handle du déclencheur et une charge utile dont les clés sont exactement ces noms de champ. Nous émettons depuis un petit service `flow/emit` à chaque changement d'état (envoyé, proposition envoyée, accepté, contre-offre, refusé, expiré, converti, plus les trois événements de validation - 10 en tout).

### Les actions : Flow → votre application

Une action déclare les champs que le marchand renseigne, et une `runtime_url` que Flow appelle en POST quand l'étape s'exécute. Nous acheminons **toutes** les actions vers un seul point d'entrée et nous aiguillons par handle :

```toml
# extensions/flow-update-quote-status/shopify.extension.toml
[[extensions]]
type = "flow_action"
name = "Update quote status"
handle = "update-quote-status"
runtime_url = "/api/flow/action"     # un seul point d'entrée pour toutes les actions
validation_url = "/api/flow/validate" # validation des champs à l'enregistrement
schema = "./schema.graphql"
return_type_ref = "QuoteActionResult"

  [[settings.fields]]
  type = "single_line_text_field"
  key = "quote_id"            # ← snake_case (l'opposé des déclencheurs !)
  required = true

  [[settings.fields]]
  type = "single_line_text_field"
  key = "target_status"       # IN_REVIEW | DECLINED | EXPIRED
  required = true
```

Le gestionnaire `/api/flow/action` vérifie le HMAC de Shopify, aiguille selon le handle de l'action, est **idempotent sur `action_run_id`** (Flow peut réessayer), et renvoie un résultat typé correspondant à `return_type_ref`. Nous avons livré trois actions : mettre à jour le statut, envoyer une notification, et attribuer à un membre de l'équipe - chacune limitée à Enterprise au point d'entrée du service, pas au niveau de la route.

### Les modèles : un point de départ qui fonctionne

Les extensions `flow_template` regroupent un fichier `.flow` (la définition du workflow) et les textes localisés. C'est ainsi qu'un marchand obtient « quand un devis de forte valeur arrive, publier dans Slack » sans le câbler lui-même. Nous en avons livré six. Le hic : les modèles n'apparaissent dans la galerie qu'**après examen par l'équipe Flow** (quelques jours ouvrés), ils suivent donc un calendrier différent du reste de votre application.

## Les pièges (chacun est une cicatrice)

| Piège | Ce qui mord | Le correctif |
|---|---|---|
| **Casse opposée des clés** | Les clés de champ des déclencheurs sont en `Casse De Titre Avec Espaces` (« Total amount ») ; celles des actions sont en `snake_case` (`quote_id`). Les mélanger donne des champs qui ne se lient jamais. | Retenez la règle. Déclencheurs en casse de titre, actions en snake_case. |
| **Tous les champs d'un déclencheur sont obligatoires** | Chaque champ déclaré **doit** être présent dans **chaque** charge utile. Un « champ de référence facultatif » est une contradiction : omettez-le une fois (un devis sans compte, sans client) et tout l'événement est rejeté. | Utilisez des champs texte simples pouvant valoir `""` plutôt que des champs de référence ; laissez les marchands brancher dans Flow avec « n'est pas vide ». |
| **Les pages de configuration ne peuvent pas enregistrer** | Les pages de configuration d'étape fournies par l'application sont en **lecture seule** - `intent.finish({properties})` ne fait rien (confirmé par Shopify). Une interface de sélection maison ne peut jamais persister son choix. | Utilisez les `[[settings.fields]]` natifs et une `validation_url` qui refuse les mauvaises valeurs à l'enregistrement. |
| **Les rappels de cycle de vie sont une extension à part** | Une extension `flow_trigger` seule ne vous dit pas qui écoute. Flow ne signale l'activation et la désactivation des workflows que par une extension distincte, `flow_trigger_lifecycle_callback`, et dès que vous en ajoutez une, un marchand ne peut activer un workflow que si votre endpoint répond par un `2xx` en moins de cinq secondes. Conditionner l'émission à des enregistrements d'abonnement que vous ne recevez jamais échoue **en position fermée** : plus personne ne reçoit d'événements. | Soit émettre pour **chaque boutique éligible**, ce que nous faisons, soit ajouter l'extension de rappel de cycle de vie et garder son endpoint rapide et disponible. |
| **Les fichiers `.flow` s'autovérifient** | Les fichiers de modèle portent une empreinte SHA-256 d'eux-mêmes et sont des exports de l'éditeur. Modifiez-en un à la main et il est rejeté. | Ne modifiez jamais un `.flow` à la main ; réexportez-le depuis l'éditeur Flow en laissant vides les champs propres au marchand. `preInstallNote` vit dans le JSON de localisation, pas dans le TOML. |
| **Un changement de schéma demande une livraison coordonnée** | Changez les champs d'un déclencheur et vos charges utiles émises doivent correspondre au schéma *déployé*. Déployez l'extension sans pousser l'émetteur (ou l'inverse) et tous les événements sont rejetés. | Livrez ensemble : `shopify app deploy` **et** la mise en production de votre serveur, au même moment. |
| **Les types sont stricts** | `number_decimal` doit être un **nombre** JSON, pas une chaîne ; un champ `*_reference` attend l'**identifiant numérique hérité**, pas le GID. | Convertissez à la frontière d'émission ; préférez les champs simples aux champs de référence (voir le piège n° 2). |

*Corrigé le 7 octobre 2026 :* la ligne sur les rappels de cycle de vie disait que les déclencheurs définis en TOML ne reçoivent aucun rappel d'abonnement ou de désabonnement et que `flowTriggerReceive` ne fait rien quand personne n'écoute. Shopify documentait déjà les rappels de cycle de vie comme une extension CLI distincte quand cet article a été écrit, et ne documente pas ce comportement silencieux ; la ligne dit donc désormais ce que dit le [guide des événements de cycle de vie](https://shopify.dev/docs/apps/build/flow/track-lifecycle-events).

Les deux premiers sont ceux qui nous ont coûté du débogage en production. La règle « tous les champs obligatoires » est particulièrement sournoise, parce qu'elle ne casse que le *sous-ensemble* d'événements auquel manque un champ - chez nous, les devis sans compte (pas d'identifiant client) et deux ou trois transitions limites - si bien que cela ressemble à un problème intermittent jusqu'à ce qu'on comprenne que c'est structurel.

## Déboguer Flow en production

Les échecs de Flow sont silencieux : une charge utile rejetée ne remonte pas au marchand. Journalisez les deux côtés de la frontière et cherchez-les :

- **Côté émission :** journalisez un `flow.emit.sent` en cas de succès et un `flow.emit.user_errors` quand `flowTriggerReceive` renvoie des `userErrors` (une incompatibilité de schéma apparaît ici).
- **Côté action :** journalisez le handle aiguillé, l'`action_run_id` et le résultat. Les échecs HMAC et les court-circuits d'idempotence doivent chacun laisser une ligne.

Quand un déclencheur « ne se déclenche pas », regardez d'abord le journal d'émission : si vous voyez `sent` sans erreur, la charge utile a été acceptée et le problème est dans le workflow du marchand ; si vous voyez `user_errors`, votre charge utile ne correspond pas au schéma déployé du déclencheur (presque toujours le piège n° 6).

## Un premier jalon raisonnable

1. **Un déclencheur** pour votre événement le plus important, avec seulement les champs dont un workflow a réellement besoin (moins de champs, moins de pièges « obligatoire »). Clés en casse de titre.
2. Émettez-le pour chaque boutique éligible depuis votre code existant de changement d'état - sans conditionner à un abonnement.
3. **Une action** qui poste vers une unique `runtime_url`, aiguillée par handle, vérifiée par HMAC, idempotente sur `action_run_id`, avec une `validation_url` plutôt qu'une page de configuration.
4. Déployez l'extension et le serveur **ensemble**, et vérifiez sur une boutique de développement avec un vrai workflow.
5. Ajoutez les modèles en dernier : ils dépendent d'un examen par l'équipe Flow, ne les laissez donc pas bloquer le lancement des déclencheurs et actions.

Déclencheurs et actions sont individuellement petits ; toute la difficulté de l'intégration tient aux règles de plateforme ci-dessus. Réglez la casse et le contrat « tous les champs obligatoires » dès le premier jour, et le reste consiste à câbler des événements que vous émettez déjà.

Si vous êtes marchand plutôt que développeur : l'intégration décrite ici est livrée dans QuotWay sous la forme des [déclencheurs et actions Shopify Flow](/features/shopify-flow), à partir de Professional - voir les [forfaits et tarifs](/pricing). Les systèmes extérieurs à Shopify, comme un ERP, un CRM ou une boutique headless, se connectent plutôt via [l'API et les webhooks QuotWay](/features/api-webhooks) sur le forfait Enterprise ; [six exemples d'intégrations](/blog/quotway-api-webhooks-recipes) montrent quels événements et quels endpoints chacune utilise.

## Pour aller plus loin

Pages Shopify revérifiées le 7 octobre 2026 ; les pièges ci-dessus viennent de notre propre construction, et la ligne sur les rappels de cycle de vie a été corrigée ce jour-là d'après le [guide des événements de cycle de vie](https://shopify.dev/docs/apps/build/flow/track-lifecycle-events) de Shopify :

- Shopify : [Flow pour les développeurs d'applications](https://shopify.dev/docs/apps/build/flow), [déclencheurs](https://shopify.dev/docs/apps/build/flow/triggers), [actions](https://shopify.dev/docs/apps/build/flow/actions), [modèles](https://shopify.dev/docs/apps/build/flow/templates)
- Centre d'aide Shopify : [Shopify Flow](https://help.shopify.com/en/manual/shopify-flow) - Flow est gratuit sur Basic, Grow, Advanced et Plus, ce qui explique que les déclencheurs et actions d'une application atteignent toute offre payante
- Article jumeau : [construire une extension d'application Shopify Sidekick](/blog/building-shopify-sidekick-app-extensions)
- À quoi servent les déclencheurs côté marchand : [Intégration ERP, CRM et PIM pour les devis B2B Shopify](/blog/shopify-b2b-erp-crm-pim-integration-patterns)
