Trackily Docs

Products

TL;DR : un native_product est une fiche produit (nom, slug, type, currency, status, images, catégorie). Crée-le depuis Settings → Commerce → Products, puis enchaîne sur ses variantes.

Ajouter un produit natif

Concept

Un product dans Trackily, c'est la fiche d'identité d'un article que tu vends en direct. Il vit dans la table native_products et il est totalement indépendant des products Shopify-synchronisés (autre table, autre pipeline). Pour ne pas mélanger les outils MCP, les commandes natives sont préfixées native_ (list_native_products, get_native_product_detail) alors que les outils Shopify gardent leurs noms d'origine (list_products, update_product…).

Un produit n'a aucun prix sur lui-même : le prix vit sur ses variantes. Même si tu vends "un seul truc à un seul prix", Trackily crée automatiquement une variante par défaut qui porte le prix. Ça uniformise la pipeline checkout et te permet de monter en complexité (taille, couleur, abonnement) sans casser ce que tu avais déjà.

Anatomie d'un produit

Champ Type Rôle
id SERIAL identifiant interne
name TEXT nom affiché ("Memo Mind — 30 jours")
slug TEXT UNIQUE utilisé dans /p/<slug>
description TEXT description longue (markdown autorisé sur la page publique)
type TEXT physical ou digital
currency TEXT ISO-3 (USD, EUR, GBP…)
status TEXT draft (masqué partout) ou active (vendable)
category TEXT catégorie libre — alimente les pills /catalog
images JSONB tableau d'objets {url, alt}
tax_rate NUMERIC(5,2) TVA en pourcent (0 = pas de tax)
shipping_cost NUMERIC(12,2) shipping fallback si aucune zone ne match
free_shipping_above NUMERIC(12,2) seuil au-dessus duquel le shipping passe à 0
allowed_domains JSONB whitelist de hosts (vide = aucune restriction)
default_payment_account_ids JSONB comptes paiement utilisés sur /p/<slug>
default_cod_enabled BOOLEAN active COD sur /p/<slug>
checkout_fields_schema JSONB personnalisation des champs du formulaire checkout
deleted_at TIMESTAMPTZ soft-delete (le produit disparaît mais ses commandes restent)

type=physical vs type=digital

  • physical — le visiteur doit fournir une adresse de livraison, le shipping est calculé, la commande passe par fulfillment (tracking number, carrier). COD (cash on delivery) est autorisé.
  • digital — pas d'adresse, pas de shipping, pas de COD. Une fois payment_status='paid', la commande passe directement en fulfillment_status='fulfilled'. C'est aussi le bon choix pour les services (abonnements, accès logiciel) et les livraisons hors-Trackily (tu factures, tu gères la livraison à part).

Comment faire (UI + MCP)

Via l'admin UI

  1. Va dans Commerce → Products (ou tape /admin#native-products directement).
  2. Clique sur + Add Product en haut à droite.
  3. Remplis :
    • Name (obligatoire) — par exemple "Memo Mind 30-day Brain Booster".
    • Slug — auto-généré depuis le name, éditable. Sert dans /p/<slug>.
    • Type — Physical ou Digital.
    • Currency — USD par défaut, ajustable par produit.
    • Description — markdown court. Apparaît sur /p/<slug> et alimente le prompt de generate_landing_for_product.
    • Category — texte libre. Sera proposé en pill sur /catalog. Voir categories.md.
    • Status — laisse en Draft tant que tu n'as pas validé tes variantes et tes paiements.
  4. Clique sur Create — Trackily crée la ligne native_products + une variante par défaut (que tu pourras remplacer ensuite).
  5. Tu atterris sur la page détail. Onglets disponibles : Variants, Images, Shipping & Tax, Checkout fields, Domains, Stats.
  6. Upload tes images depuis l'onglet Images (drag-drop ou URL externe — stockées en native_product_assets, max 10 MB par fichier).
  7. Quand tout est prêt, passe le status à Active. Le produit devient vendable.

Via MCP

L'outil MCP commerce-native pour la création de produit est create_product (côté ecommerce-tools — même tool sert pour Shopify et le natif, distingué par le payload). Pour le natif tu peux passer par le proxy admin REST :

{
  "name": "create_product",
  "arguments": {
    "platform": "native",
    "name": "Memo Mind — 30 jours",
    "slug": "memo-mind",
    "type": "physical",
    "currency": "EUR",
    "description": "Booster de mémoire formulé pour les adultes 40+. Cure de 30 jours, 1 gélule par jour.",
    "category": "Suppléments cognitifs",
    "status": "draft",
    "tax_rate": 20.00,
    "shipping_cost": 4.90,
    "free_shipping_above": 50.00
  }
}

Lister les produits existants :

{
  "name": "list_native_products",
  "arguments": {
    "status": "active",
    "type": "physical",
    "search": "memo",
    "limit": 50
  }
}

Réponse type (extrait) :

{
  "status": "ok",
  "count": 1,
  "products": [
    {
      "id": 12,
      "name": "Memo Mind — 30 jours",
      "slug": "memo-mind",
      "type": "physical",
      "currency": "EUR",
      "status": "active",
      "images": [{ "url": "/product-assets/47/box.webp", "alt": "Memo Mind box" }],
      "variant_count": 3,
      "price_from": "29.90",
      "price_to": "79.90",
      "total_stock": 412,
      "has_unlimited_stock": false
    }
  ]
}

Récupérer le détail complet (avec ses options + variantes) :

{
  "name": "get_native_product_detail",
  "arguments": {
    "product_id": 12
  }
}

Mettre à jour un champ :

{
  "name": "update_product",
  "arguments": {
    "platform": "native",
    "product_id": 12,
    "patch": {
      "status": "active",
      "tax_rate": 20.00,
      "free_shipping_above": 39.00
    }
  }
}

Supprimer (soft-delete — les commandes historiques sont conservées, le produit disparaît de toutes les listes et de la pipeline checkout) :

{
  "name": "delete_product",
  "arguments": {
    "platform": "native",
    "product_id": 12
  }
}

Note Tier-2. update_product et delete_product sont des outils Tier-2 : le premier appel renvoie un confirm_token, le deuxième (avec le token) exécute. C'est la garantie qu'un agent MCP ne peut pas casser ton catalogue sans validation explicite. Voir docs/mcp/ pour le détail du système Tier.

Génération AI d'une landing à partir d'un produit

Une fois ton produit en status='active', l'outil le plus utile pour aller vite, c'est generate_landing_for_product. Il lit le produit (nom, description, type, variantes, prix), construit le prompt, génère une landing complète et la sauvegarde en mode draft avec product_id déjà rempli + les payment_account_ids que tu lui passes.

{
  "name": "generate_landing_for_product",
  "arguments": {
    "product_id": 12,
    "language": "fr",
    "vertical": "supplements",
    "framework": "pas",
    "traffic_temperature": "warm",
    "payment_account_ids": [3, 5],
    "cod_enabled": true
  }
}

Réponse première étape (preview + confirm_token) :

{
  "status": "confirmation_required",
  "tool": "generate_landing_for_product",
  "preview": {
    "product": { "id": 12, "name": "Memo Mind — 30 jours", "variants_count": 3 },
    "ai_inputs": {
      "vertical": "supplements",
      "language": "fr",
      "framework": "pas",
      "traffic_temperature": "warm",
      "description_preview": "Product \"Memo Mind — 30 jours\" (physical good). Seller-provided description: Booster de mémoire …"
    },
    "checkout_links": { "payment_account_ids": [3, 5], "cod_enabled": true },
    "cost_note": "This call will consume LLM tokens (~5-8k output) and create one new landing_pages row in draft status."
  },
  "confirm_token": "tk_abc123…"
}

Tu rejoues l'appel avec confirm_token pour exécuter. La landing créée pointe sur ton produit, les boutons Stripe / PayPal / COD sont déjà câblés sous le formulaire.

Anti-leak avec allowed_domains

Par défaut, n'importe qui peut cloner le HTML de ta landing publique, l'héberger sur son propre domaine et garder le bloc checkout pointé sur ton Stripe — ce qui revient à te faire vendre pour son compte. Pour s'en protéger :

{
  "name": "update_product",
  "arguments": {
    "platform": "native",
    "product_id": 12,
    "patch": {
      "allowed_domains": ["lp.monsite.com", "store.monsite.com"]
    }
  }
}

Effet : le bloc checkout et la route /p/memo-mind ne rendent plus quand la requête arrive depuis un host hors whitelist. Le formulaire de soumission de reviews /api/reviews applique la même règle (voir reviews.md) pour qu'un concurrent ne puisse pas non plus polluer tes avis. Laisse le tableau vide pour ne pas restreindre.

Page publique /p/<slug>

Chaque produit en status='active' a sa page autonome à /p/<slug> (par exemple https://lp.monsite.com/p/memo-mind). Elle :

  • affiche images, titre, prix, description, sélecteur de variante, formulaire checkout, bloc de reviews ;
  • utilise default_payment_account_ids + default_cod_enabled du produit (pas besoin d'une landing dédiée) ;
  • respecte allowed_domains ;
  • est listée sur /catalog (la grille des produits actifs).

Page produit publique

C'est l'option la plus rapide pour vendre un produit "tel quel" sans construire une landing AI. Pour des angles marketing variés, garde le produit + génère plusieurs landings.

Exemples concrets

1. Supplément 30 jours, marché FR

{
  "name": "create_product",
  "arguments": {
    "platform": "native",
    "name": "Memo Mind — 30 jours",
    "type": "physical",
    "currency": "EUR",
    "description": "Booster de mémoire pour adultes 40+. 30 gélules.",
    "category": "Suppléments cognitifs",
    "status": "draft",
    "tax_rate": 20.00,
    "shipping_cost": 4.90,
    "free_shipping_above": 50.00
  }
}

Suite logique : ajouter 3 variantes "30 jours / 60 jours / 90 jours" (voir variants.md), créer une zone shipping FR + une zone rest-of-world (shipping.md), connecter Stripe (stripe-connect.md), passer status='active'.

2. Ebook digital, prix unique

{
  "name": "create_product",
  "arguments": {
    "platform": "native",
    "name": "Cold Email Playbook 2026",
    "type": "digital",
    "currency": "USD",
    "description": "120 pages. 14 frameworks éprouvés. Templates inclus.",
    "category": "Ebooks",
    "status": "active"
  }
}

Pas de shipping, pas de COD. Une seule variante à $29, lien de download envoyé via la séquence email post-purchase (voir email/sequences.md).

3. Mini-store sur un domaine custom

Tu as 5 produits, tu veux un mini-shop à l'adresse store.monsite.com. Workflow :

  1. Crée les 5 produits avec catégories cohérentes (par exemple "Boissons", "Snacks", "Compléments").
  2. Set allowed_domains à ["store.monsite.com"] sur chacun.
  3. Set default_payment_account_ids + default_cod_enabled sur chacun.
  4. Configure le domaine store.monsite.com avec root_behavior='catalog' (voir docs/campaigns/domains.md).
  5. Attache les 5 produits au domaine via domain_native_products.
  6. Le visiteur qui arrive sur store.monsite.com/ voit la grille catalog, clique sur un produit, achète. Toujours pas de Shopify.

Erreurs courantes

  • "Le slug est déjà pris"slug est UNIQUE. Si tu refais un test, soft-delete l'ancien produit (il libère le slug ? non, l'unique tient même sur les soft-deleted) → préfixe avec une date (memo-mind-2026-05).
  • "Le produit n'apparaît pas sur /catalog" — il est encore en status='draft', ou il n'a aucune variante active, ou la requête tape un host non whitelisté.
  • "Mes images sont rejetées"validateUpload plafonne à 10 MB et n'accepte qu'image/* + application/pdf. Compresse les hero shots en WebP (voir docs/landings/image-providers.md).
  • "J'ai passé type='digital' mais le checkout demande l'adresse" — vérifie que ta landing utilise bien le product_id modifié (le bloc checkout est généré à la création de la landing, mais il se reconfigure à la volée à l'affichage en fonction du type courant du produit).
  • "generate_landing_for_product me dit que payment_account_ids n'existent pas" — l'outil refuse silencieusement les IDs invalides ou inactifs. Liste d'abord list_payment_accounts (admin REST) pour vérifier.
  • "J'ai mis tax_rate=20 mais le checkout affiche tax=0" — la tax est appliquée après le discount. Si le code promo couvre tout le subtotal, la tax tombe à 0. Sinon, contrôle que le produit a bien le tax_rate (et pas la variante — la tax vit sur le produit, pas par variante).

Voir aussi