Commerce native
TL;DR : vends tes propres produits physiques ou digitaux directement depuis Trackily, sans Shopify, sans WooCommerce — checkout, paiement, livraison, remboursement, tout est intégré.

Concept
Le module Commerce native transforme Trackily en plateforme e-commerce complète. Tu sors la carte bancaire de tes visiteurs sans dépendre d'un Shopify externe : un produit créé dans Trackily devient instantanément vendable sur n'importe quelle landing page de ton compte, et chaque commande remonte dans la même base que tes clics, tes leads et tes conversions affiliate.
C'est volontairement un Shopify-like simplifié, pas un clone. L'objectif n'est pas de couvrir 100 % des cas d'usage d'un retailer multi-canal, mais de couvrir les 90 % qui comptent pour un media buyer qui veut tester un produit en direct sans payer la dîme à un SaaS tiers :
- 1 produit physique ou digital avec variantes (taille, couleur…)
- 1 landing AI avec bloc checkout intégré
- 1 compte Stripe ou PayPal connecté (en un clic depuis la Phase 18)
- 1 zone de shipping géo + tarifs
- 1 code promo de lancement
- Une page
/p/<slug>standalone si tu veux vendre sans landing complète - Un catalogue
/catalogsi tu veux servir plusieurs produits sur le même domaine
Tout le reste — emails post-purchase, abandoned cart, reviews, fulfillment, refunds — s'empile par-dessus sans que tu doives changer d'outil.
Quand utiliser Commerce native vs intégration Shopify
Trackily supporte deux mondes en parallèle :
| Critère | Commerce native | Intégration Shopify |
|---|---|---|
| Tu vends en direct ? | oui | non (Shopify héberge) |
| Catalogue | native_products (DB Trackily) |
sync depuis stores (Shopify) |
| Checkout | Bloc checkout sur la landing OU page /p/<slug> |
Cart Shopify (off-site) |
| Paiements | Stripe Connect / PayPal multi-compte | Géré par Shopify |
| Attribution click vers vente | Native (orders.click_id) | Webhook Shopify vers conversions |
| Variantes | Jusqu'à 3 axes, prix + stock par variante | Calquées sur Shopify |
| Reviews, discounts, shipping zones | Tout en interne | Délégué à Shopify |
| Inventaire | Stock par variante (-1 = illimité) | Sync inventory levels |
| Idéal pour | Tester un produit, mini-store, dropshipping affilié | Site marchand existant, gros catalogue |
Tu peux faire tourner les deux en parallèle. Une campagne peut pointer soit sur un native_product_id, soit sur un offer_id affilié, soit sur un product_id Shopify-synchronisé. Les trois chemins remontent dans le même reporting unifié.
Le reste de cette section couvre uniquement le commerce native. Pour la partie Shopify, voir la section dédiée dans docs/admin-ui/.
Architecture et data model
Voici le schéma simplifié des tables qui font tourner le commerce native. Tu n'as jamais besoin d'écrire de SQL — c'est juste pour comprendre ce qui se passe sous le capot quand tu cliques.
┌──────────────────────┐
│ native_products │ ← le produit (nom, type, currency)
│ (slug, status, │
│ category, images, │
│ tax_rate, │
│ shipping_cost, │
│ allowed_domains) │
└─────────┬────────────┘
│ 1..N
┌─────────────────┴─────────────────────┐
▼ ▼
┌──────────────────────────┐ ┌──────────────────────────┐
│ native_product_options │ │ native_product_variants │ ← une ligne
│ (Color, Size, Material) │ │ (option1/2/3_value, │ par
│ position 0/1/2, values) │ │ price, sku, stock, │ combinaison
└──────────────────────────┘ │ image_url, is_active) │
└────────────┬─────────────┘
│ référencé par
▼
┌──────────────────────────┐ ┌──────────────────────────┐
│ landing_pages │ │ orders │ ← commande
│ product_id, payment_ │◀───│ customer_email, │
│ account_ids[], cod_ │ │ shipping_address, │
│ enabled, price_ │ │ subtotal/shipping/tax/ │
│ overrides │ │ discount/total, │
└──────────────────────────┘ │ payment_status, │
│ fulfillment_status, │
│ landing_id, │
│ click_id, ← attribution │
│ campaign_id, │
│ source_id, │
│ payment_account_id, │
│ payment_reference │
└────────────┬─────────────┘
│ 1..N
┌────────────────────────┼────────────────────────┐
▼ ▼ ▼
┌─────────────────────┐ ┌─────────────────────┐ ┌─────────────────────┐
│ order_items │ │ order_transactions │ │ product_reviews │
│ (variant snapshot: │ │ (kind: authorize/ │ │ (rating 1-5, body, │
│ product_name, sku, │ │ capture/refund, │ │ status pending/ │
│ unit_price, │ │ amount, provider, │ │ approved/rejected, │
│ quantity) │ │ provider_reference)│ │ verified_purchase) │
└─────────────────────┘ └─────────────────────┘ └─────────────────────┘
┌────────────────────┐ ┌────────────────────┐ ┌────────────────────┐
│ payment_accounts │ │ shipping_zones │ │ discount_codes │
│ (Stripe, PayPal, │ │ (country_codes[], │ │ (percent / fixed / │
│ COD ; api_secret, │ │ is_rest_of_world) │ │ free_shipping ; │
│ oauth_access_ │ │ │ │ │ product_id NULL = │
│ token, │ │ │ 1..N │ │ global ; max_uses)│
│ webhook_secret ; │ │ ▼ │ └────────────────────┘
│ mode live/test ; │ │ shipping_rates │
│ oauth_user_id) │ │ (name, price, │
└────────────────────┘ │ currency, │
│ min/max_order_ │
│ amount) │
└────────────────────┘
Les tables clé en une phrase
native_products— la fiche produit (nom, slug, description, type physical/digital, currency, status draft/active, catégorie, images, tax_rate, shipping_cost, allowed_domains). Une seule ligne par produit, même quand il a 18 variantes.native_product_options— les axes de variante (Color, Size, Material). Maximum 3 par produit, identifiés parposition0/1/2. Le champvaluesest un tableau JSON des valeurs possibles.native_product_variants— une ligne par combinaison cartésienne d'options. Porte le prix unitaire, le SKU, le stock (-1 = illimité), l'image de variante et le flagis_active.orders— une ligne par commande. Capture l'email + adresse client, les totaux décomposés (subtotal/shipping/tax/discount/total), le statut paiement, le statut fulfillment, et surtout les colonnes d'attribution (landing_id,click_id,campaign_id,source_id) qui sont la raison d'être de tout ça.order_items— une ligne par variante achetée. Snapshoteproduct_name,variant_label,sku,unit_priceau moment de l'INSERT pour que les commandes historiques survivent à un edit ou un soft-delete du produit.order_transactions— ledger d'audit pour chaque événement de paiement (authorize, capture, refund, void). Conserve laraw_responsecomplète du provider pour les disputes.payment_accounts— les comptes Stripe / PayPal connectés. Multi-compte natif : tu peux router différentes landings sur différents comptes Stripe. Voir payment-accounts.md et stripe-connect.md.shipping_zones+shipping_rates— regroupement de pays + N tarifs par zone. Une zone "rest-of-world" (unique en base) sert de catch-all.discount_codes— codes promo percent / fixed / free_shipping, avec limites d'usage, dates de validité etmin_order_amount.product_reviews— étoiles + commentaires soumis publiquement sur/p/<slug>. Modération par défaut, badgeverified_purchasecalculé à l'insertion.
Flux d'une vente
- Visiteur clique sur ta source →
/c/<slug>(Trackily) → cookieclick_id. - Redirection vers la landing → le visiteur voit le bloc checkout sous le formulaire (composé des boutons "Pay with Stripe", "Pay with PayPal", "Cash on delivery" selon ce que tu as activé).
- Il choisit sa variante, remplit son adresse, clique sur un bouton.
POST /api/order→ Trackily crée la ligneordersenpayment_status='pending', snapshote le panier dansorder_items, calcule le shipping viashipping_zones, applique le code promo, redirige vers Stripe Checkout / PayPal / page de confirmation COD.- Webhook
checkout.session.completed(ou validation manuelle pour COD) →payment_status='paid',paid_at=NOW(), stock décrémenté atomiquement. - Tu fulfilles la commande depuis
/admin#ordersou via MCPfulfill_native_order(tracking number + carrier). - Si remboursement :
refund_native_order→ appel API Stripe/PayPal →payment_status='refunded'ou'partial_refund', stock restocké.
À chaque étape, la colonne click_id reste collée à la commande — ton ROAS par campagne est calculé sans dépendre d'un pixel tiers.
Ce qui est dans cette section
Onze pages couvrent l'ensemble du module. Aborde-les dans cet ordre si tu démarres :
- products.md — créer ton premier produit (UI + MCP
create_product/list_native_products/get_native_product_detail). - variants.md — décliner ce produit en variantes (couleur, taille, prix par variante).
- categories.md — organiser le catalogue et les filter pills de la page
/catalog. - payment-accounts.md — connecter Stripe et PayPal (manuel).
- stripe-connect.md — la nouvelle voie OAuth en un clic (Phase 18).
- shipping.md — zones géographiques et tarifs de livraison.
- discounts.md — codes promo et leurs règles d'application.
- reviews.md — collecter et modérer les avis clients.
- orders.md — le cœur du module : cycle de vie des commandes.
- fulfillment.md — expédier les commandes et joindre le tracking.
- refunds.md — rembourser partiellement ou totalement.
Pré-requis avant de vendre
Pour ouvrir le premier checkout fonctionnel, tu as besoin au minimum de :
- 1 produit en
status='active'avec au moins 1 varianteis_active=true - 1 zone de shipping qui couvre les pays que tu vises (ou la zone rest-of-world)
- 1 compte de paiement connecté OU
cod_enabled=truesur la landing (cash on delivery) - 1 landing avec son
product_idrempli OU la page/p/<slug>du produit
Le reste (reviews, discounts, emails post-purchase) est optionnel mais fortement recommandé pour la conversion.
Erreurs courantes au démarrage
- "Pourquoi le bloc checkout n'apparaît pas ?" — la landing n'a pas son
product_idrempli, ou le produit est enstatus='draft', ou aucunpayment_account_idsn'est attaché ETcod_enabled=false. Va dans le détail de la landing puis dans l'onglet Commerce. - "L'order reste 'pending' alors que Stripe a encaissé" — le webhook n'a pas tapé sur ton instance. Vérifie l'URL de webhook Stripe dans ton compte Connect (doit pointer sur
/webhook/stripe/native-pending). Avec la Phase 18 OAuth, le webhook est créé automatiquement. - "Erreur 'A rest-of-world zone already exists'" — il ne peut y avoir qu'une seule zone
is_rest_of_world=truesystem-wide. Edit l'existante au lieu d'en créer une deuxième. - "Mon SKU custom ne se sauvegarde pas" — vérifie que la variante a bien
is_active=true. Une variante inactive est ignorée par toute la pipeline (catalog, checkout, stock). - "Le visiteur voit le checkout d'un produit cloné par un concurrent" — utilise
allowed_domains(JSONB array surnative_products) pour whitelister les hosts autorisés. Voir products.md.
Voir aussi
- Landings → AI builder — comment générer une landing AI déjà câblée à un produit via
generate_landing_for_product. - Landings → A/B price testing — dupliquer une landing avec prix différent pour split-tester.
- Automizer → Rules — déclencher des règles automatiques sur les commandes (auto-fulfill, alert anomalie revenue).
- Email → Sequences — séquences post-purchase et abandoned cart, branchées sur les campaigns.
- MCP → Tools reference — la liste exhaustive des outils MCP commerce avec leurs schémas JSON.