Votre boutique en ligne enregistre toutes ses ventes, mais Google Analytics 4 (GA4) n'en voit qu'une partie. Avec l'API des ventes, votre serveur envoie chaque vente à takotak au moment où elle est payée. Vous n'avez plus de fichier à déposer dans Mes ventes, et takotak travaille sur vos vraies ventes : bilan, courbe de Mes actions, panier moyen, marge, et comparaison avec ce que déclarent Google Ads et Meta.

Cette page s'adresse au développeur qui branche l'envoi. L'appel se place au même endroit que l'envoi de la vente à GA4 par le Measurement Protocol, décrit dans Remontée des ventes : le webhook du prestataire de paiement, le back-office ou la base de commandes. Faites les deux au même endroit. takotak a vos ventes tout de suite, et GA4 finit par les voir toutes.

La clé et l'adresse

Créez la clé dans votre espace client : Mes ventes › Envoi automatique › Créer une clé. Elle désigne votre site : l'adresse de l'API est la même pour tous.

https://app.takotak.ai/api/v1/sales

Chaque appel porte la clé dans l'en-tête Authorization: Bearer tks_…. Gardez-la côté serveur, dans une variable d'environnement, jamais dans une page. Elle permet d'écrire vos ventes. Elle est distincte des clés de l'API des articles et de la newsletter.

« Remplacer la clé » invalide l'ancienne aussitôt : il n'y a pas de période où les deux marchent. Déployez la nouvelle clé juste après, et renvoyez les lots refusés entre-temps (401) : la reference évite les doublons. « Arrêter l'envoi automatique » retire la clé. Les jours déjà reçus restent couverts par vos ventes ; les jours suivants reviennent à GA4.

Envoyer des ventes

POST https://app.takotak.ai/api/v1/sales
Authorization: Bearer tks_…
Content-Type: application/json
{
  "sales": [
    {
      "reference": "CMD-2026-10481",
      "date": "2026-10-21T14:03:00+02:00",
      "amount": 89.9,
      "currency": "EUR",
      "margin": 31.5,
      "gclid": "Cj0KCQjw…"
    }
  ]
}

Un lot contient de 0 à 1 000 ventes. Envoyez la vente au passage en « payée », une par appel ou par petits lots. Pour l'historique d'avant le premier appel, déposez plutôt un export dans Mes ventes (voir « La période couverte »).

Réponse 200 :

{
  "site": "ma-boutique.fr",
  "version": "2026-10-22",
  "received": 1,
  "added": 1,
  "updated": 0,
  "removed": 0,
  "refunded": 0,
  "unknown": 0,
  "ignoredFields": [],
  "linked": 1,
  "coverage": { "since": "2026-10-21", "until": "2026-10-21", "lastCallAt": "2026-10-21T12:03:04.512Z", "received": 1 }
}
Champ Sens
added, updated ventes créées, et ventes déjà connues mises à jour
removed ventes retirées (annulées, remboursées en entier)
refunded commandes remboursées en partie (vente reçue ou achat vu par GA4), désormais comptées pour leur montant net
unknown annulations ou remboursements d'une référence que takotak ne connaît ni en vente ni en achat vu par GA4 : sans effet
ignoredFields champs que takotak ne connaît pas : ignorés, jamais stockés. Vérifiez qu'il ne s'agit pas d'une faute de frappe.
linked paires vente ↔ achat GA4 après ce lot, sur tout le site ; null quand le lot ne change aucune vente (lot vide) : le rapprochement n'est pas refait
coverage la période où takotak tient vos ventes pour complètes (voir plus bas)

Les champs d'une vente

Champ Obligatoire Valeur
reference oui votre numéro de commande, le même que le transaction_id envoyé à GA4 : c'est lui qui relie la vente à l'achat vu par GA4, et qui identifie la vente d'un appel à l'autre.
date oui l'heure du paiement en ISO 8601 avec son fuseau : 2026-10-21T14:03:00+02:00 ou 2026-10-21T12:03:00Z. takotak range la vente au jour du fuseau de votre site (celui de vos dépôts, Paris par défaut) : 2026-10-21T23:30:00-04:00 est une vente du 22 à Paris. Une date seule (2026-10-21) est acceptée, telle quelle. Pas de date avant 2000.
amount oui ce que le client a payé, toutes taxes et frais de port compris, en nombre (89.9, point décimal).
currency non code ISO 4217 sur trois lettres ; EUR pour une vente nouvelle, la devise déjà reçue pour une mise à jour.
ga4Amount non le montant envoyé à GA4 en value, s'il diffère (hors taxes, sans frais de port) : il aide le rapprochement.
margin non ce qui vous reste sur la vente, en montant dans la devise de la vente (31.5), pas en pourcentage. Sans elle, takotak prend le montant × la marge de vos réglages.
status non paid par défaut ; pending, cancelled ou refunded retirent la vente, sauf refunded avec un refundAmount partiel, qui la garde pour son net (voir plus bas).
refundAmount non avec status: "refunded" seulement : le total remboursé à ce jour sur la commande, pour un remboursement partiel (voir plus bas).
channel non d'où vient la vente, si votre site le sait : google ads, meta ads, newsletter, partenaire…
gclid, gbraid, wbraid non l'identifiant du clic Google Ads gardé avec la commande.
utmSource, utmMedium non les paramètres utm_source et utm_medium de la visite qui a mené à la commande.
fbclid, ttclid non l'identifiant du clic Facebook ou TikTok.

Le canal de la vente

Le canal est ce qui permet à takotak de vérifier chaque régie publicitaire : comparer les conversions que Google Ads ou Meta s'attribuent aux ventes qui viennent vraiment de leurs clics. Sans canal, takotak ne connaît la provenance que des ventes que GA4 a vues, et la comparaison avec chaque régie en devient moins sûre.

Au moment de la commande, gardez avec elle l'identifiant du clic et les utm de la visite (paramètres de l'adresse d'arrivée, à conserver en session ou en cookie jusqu'au paiement). takotak déduit le canal dans cet ordre :

  1. channel, s'il est envoyé ;
  2. gclid, gbraid ou wbraid : Google Ads ;
  3. utmSource et utmMedium : facebook / cpc, par exemple ;
  4. fbclid ou ttclid : Facebook ou TikTok, payant ou non (ces identifiants sont aussi posés sur les clics des publications ordinaires).

Seul le canal déduit est gardé : les identifiants de clic ne sont pas stockés.

Mises à jour, annulations, remboursements

Une vente est identifiée par sa reference, sans tenir compte d'un # initial ni des majuscules (#CMD-1042 et cmd-1042 sont la même commande). La renvoyer met la vente à jour : envoyer deux fois la même vente ne la compte donc jamais deux fois, et un webhook rejoué ne pose aucun problème.

  • Mise à jour (montant corrigé) : renvoyez la vente avec reference, date et le nouveau amount. Les champs facultatifs absents gardent leur valeur : le canal et la devise reçus à la commande restent. Une date sans heure qui change le jour de la vente efface l'heure gardée.
  • Remboursement partiel : { "reference": "CMD-2026-10481", "status": "refunded", "refundAmount": 20 }. refundAmount est le total remboursé à ce jour sur la commande, pas le montant de ce remboursement-ci : un second remboursement de 15 € s'envoie avec 35. Un webhook rejoué ou arrivé en retard ne compte donc rien deux fois : le plus grand total reçu fait foi. Il se compte sur la même base que amount (taxes et port compris). La vente compte pour son montant moins ce total, et le garde si vous la renvoyez ensuite en paid. À 95 % ou plus du montant, elle est retirée comme un remboursement complet.
  • Annulation ou remboursement complet : { "reference": "CMD-2026-10481", "status": "refunded" } suffit (ou cancelled). La vente disparaît de vos ventes.
  • L'achat vu par GA4 suit : un remboursement ou une annulation s'applique aussi à l'achat que GA4 a reçu sous ce numéro de commande, même si takotak n'a jamais reçu la vente (une commande d'avant votre premier appel, par exemple). Il ne compte plus, ou compte pour son net ; si vous avez envoyé ga4Amount, le remboursement lui est rapporté dans la même proportion. Envoyez le remboursement avec la vente (dans le même lot) ou après elle, jamais dans un lot qui la précède.
  • Commande en attente de paiement : ne l'envoyez pas, ou envoyez-la en pending. Elle ne compte qu'une fois envoyée en paid. Un achat que GA4 aurait reçu sous ce numéro n'est pas touché.

La période couverte

takotak tient vos ventes pour complètes du jour du premier appel jusqu'au jour du dernier, jours comptés à l'heure de Paris. Tant que l'envoi est actif (un appel depuis moins de deux jours), la journée en cours est couverte aussi : un jour sans appel est un jour sans vente. Sur cette période, elles remplacent GA4, comme un dépôt de fichier : un achat vu par GA4 sans vente en face n'y compte jamais, vos ventes font foi. Envoyez l'heure de chaque vente (date avec heure et fuseau) : l'onglet Aujourd'hui compte alors la journée sur vos ventes, sans le retard de GA4 ; une seule vente sans heure dans la journée la renvoie à GA4.

Le début de la période ne recule jamais : une correction tardive d'une commande de mars met la vente à jour, mais ne rend pas « complets » les mois où rien n'était envoyé. Une vente antérieure au premier appel ne compte que sur une période couverte par un dépôt.

Trois conséquences :

  • Une journée sans vente s'annonce par un lot vide : { "sales": [] }, par exemple chaque soir avant minuit (heure de Paris) par une tâche planifiée. Sans appel, takotak ne sait pas si vous n'avez rien vendu ou si l'envoi s'est arrêté : il revient alors à GA4 pour ces jours-là.
  • Après deux jours sans appel, Mes actions affiche « Relancer l'envoi automatique de vos ventes ».
  • Pour reprendre votre historique, déposez un export de vos ventes dans Mes ventes › Déposer mes ventes : il couvre sa propre période, du premier au dernier jour du fichier.

Avec les dépôts de fichier

Les deux se combinent. Un fichier déposé dans Mes ventes remplace toutes les ventes de sa période, du premier au dernier jour du fichier, y compris celles reçues par l'API. Une vente envoyée ensuite par l'API, avec un numéro de commande déjà déposé, met à jour la vente déposée.

Aucune donnée personnelle

takotak ne reçoit ni nom, ni e-mail, ni téléphone, ni adresse, ni identifiant client. Un champ de ce genre (email, phone, name, firstName, address, customer, client…), ou une valeur qui contient une adresse e-mail, dans n'importe quel champ, refuse tout le lot. Le numéro de commande suffit.

Erreurs

Un lot est accepté en entier ou refusé en entier : sur une erreur, rien n'est enregistré.

Réponse Cas
400 Corps illisible : JSON attendu, de la forme { "sales": [ … ] }.
401 Clé absente, fausse, remplacée ou retirée.
413 Plus de 1 000 ventes, ou plus de 1 Mo.
422 Une vente au moins est refusée : errors donne pour chacune sa position dans le lot (index, à partir de 0), sa référence et la raison (20 au plus).
{
  "error": "Lot refusé : rien n'a été enregistré. Corrigez les ventes indiquées et renvoyez le lot.",
  "errors": [
    { "index": 3, "reference": "CMD-2026-10484", "error": "« date » : précisez le fuseau horaire (Z ou +02:00), sinon l'heure est ambiguë." }
  ]
}

Sur une erreur réseau ou une réponse 5xx, renvoyez le même lot plus tard : la reference évite les doublons. Gardez sur la commande la trace d'un envoi réussi, et alertez-vous quand une commande payée n'en a pas.

Vérifier la clé

GET https://app.takotak.ai/api/v1/sales
Authorization: Bearer tks_…

La réponse donne le site de la clé et la période couverte, sans rien enregistrer :

{
  "site": "ma-boutique.fr",
  "version": "2026-10-22",
  "coverage": { "since": "2026-10-21", "until": "2026-10-22", "lastCallAt": "2026-10-22T19:00:02.118Z", "received": 37 }
}

since et until sont null tant qu'aucun lot n'a été reçu avec cette clé.

Exemples

curl :

curl -X POST https://app.takotak.ai/api/v1/sales \
  -H "Authorization: Bearer $TAKOTAK_SALES_KEY" \
  -H "Content-Type: application/json" \
  -d '{"sales":[{"reference":"CMD-2026-10481","date":"2026-10-21T14:03:00+02:00","amount":89.9,"gclid":"Cj0KCQjw"}]}'

Le remboursement de 20 € d'une partie de cette commande :

curl -X POST https://app.takotak.ai/api/v1/sales \
  -H "Authorization: Bearer $TAKOTAK_SALES_KEY" \
  -H "Content-Type: application/json" \
  -d '{"sales":[{"reference":"CMD-2026-10481","status":"refunded","refundAmount":20}]}'

Node.js, au passage de la commande en « payée » :

async function sendSaleToTakotak(order) {
  const res = await fetch("https://app.takotak.ai/api/v1/sales", {
    method: "POST",
    headers: { authorization: `Bearer ${process.env.TAKOTAK_SALES_KEY}`, "content-type": "application/json" },
    body: JSON.stringify({
      sales: [{
        reference: order.number,            // le transaction_id envoyé à GA4
        date: order.paidAt.toISOString(),    // heure du paiement, en UTC
        amount: order.total,
        currency: order.currency,
        margin: order.margin ?? undefined,
        gclid: order.gclid ?? undefined,     // gardés avec la commande à l'arrivée sur le site
        utmSource: order.utmSource ?? undefined,
        utmMedium: order.utmMedium ?? undefined,
      }],
    }),
  });
  if (!res.ok) throw new Error(`takotak ${res.status} : ${await res.text()}`);
}

PHP, pour WooCommerce (WordPress), au passage de la commande en « payée » :

$paid = $order->get_date_paid() ?: $order->get_date_created();
$payload = ['sales' => [[
  // Le même numéro que le transaction_id envoyé à GA4 : selon l'extension GA4, get_order_number() ou get_id().
  'reference' => (string) $order->get_order_number(),
  'date'      => $paid->format(DATE_ATOM),
  'amount'    => (float) $order->get_total(),
  'currency'  => $order->get_currency(),
  'gclid'     => $order->get_meta('_gclid') ?: null,
]]];
$response = wp_remote_post('https://app.takotak.ai/api/v1/sales', [
  'headers' => ['Authorization' => 'Bearer ' . TAKOTAK_SALES_KEY, 'Content-Type' => 'application/json'],
  'body'    => wp_json_encode($payload),
  'timeout' => 10,
]);
if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) {
  // À renvoyer plus tard : la commande garde la trace d'un envoi manqué.
  $order->update_meta_data('_takotak_sent', 'no');
} else {
  $order->update_meta_data('_takotak_sent', 'yes');
}
$order->save();

Dans cet exemple, le gclid n'existe que si votre site l'a gardé avec la commande, ici dans une méta _gclid. Vérifiez quel numéro votre extension GA4 envoie en transaction_id : beaucoup envoient l'identifiant interne (get_id()) et non le numéro affiché. Pour PrestaShop ou un site sur mesure, l'appel est le même : un POST JSON au passage en « payée ».

La liste de contrôle

  1. Clé créée dans Mes ventes › Envoi automatique, gardée côté serveur.
  2. Un appel au passage en « payée », au même endroit que l'envoi purchase à GA4, avec le même numéro de commande.
  3. date avec fuseau, amount, et si possible margin et le canal (channel, gclid, utm).
  4. status: "cancelled" à l'annulation, "refunded" au remboursement : sans montant s'il est complet, avec refundAmount (le total remboursé à ce jour) s'il est partiel.
  5. Un lot vide chaque jour, pour que takotak sache qu'il ne manque rien.
  6. Historique d'avant le premier appel repris par un dépôt CSV dans Mes ventes.
  7. Aucune donnée personnelle dans l'envoi.