L'API Grapify fait remonter toute seule les clients et les commandes de votre boutique en ligne, suit leurs changements de statut, et prévient votre boutique quand une commande avance dans Grapify. Une clé suffit, créée en un clic dans vos réglages.
Toutes les adresses de l'API commencent par l'adresse ci-dessous. Les échanges se font en JSON.
https://hdwcgplfjkofvytvibap.supabase.co/functions/v1/api/v1Dans Grapify : Réglages → Connexions → Intégrations → API Grapify → « Créer une clé ». Cochez « Autoriser aussi l'envoi de données » pour envoyer des clients et des commandes. La clé ne s'affiche qu'une fois.
Ajoutez l'en-tête Authorization: Bearer suivi de la clé. Elle agit avec les droits de la personne qui l'a créée : un collaborateur ne voit par l'API que ce qu'il voit à l'écran.
Appelez /ping : la réponse dit si la clé est valide et si elle peut écrire.
curl https://hdwcgplfjkofvytvibap.supabase.co/functions/v1/api/v1/ping \
-H "Authorization: Bearer grp_live_xxxxxxxx"
{ "ok": true, "can_write": true }Pour vos essais, utilisez un compte de démonstration plutôt que votre compte de production : demandez-le à support@grapify.be.
La description OpenAPI détaille chaque champ ; elle s’importe dans Postman ou dans un générateur de code.
GET/pingVérifier la clé et ses droits.LectureGET/productsLister vos produits actifs avec leur SKU (les produits archivés ne sont jamais renvoyés). Filtre ?sku=, pagination ?page= et ?limit=.LectureGET/stockConnaître le stock disponible de chaque produit : en stock (lots utilisables), réservé par les commandes en cours, disponible. Filtre ?sku=.LectureGET/customersRetrouver un client par son e-mail (?email=).LectureGET/customers/{id}Lire un client par son identifiant Grapify.LecturePUT/customersCréer ou mettre à jour un client : nom, e-mail, téléphone, société, TVA, adresses. Dédoublonné par l'e-mail.Clé lecture et écriturePOST/ordersCréer une commande liée au client : lignes, frais de livraison, remise, totaux, statut de paiement.Clé lecture et écritureGET/ordersLister les commandes de l’API modifiées depuis une date (?updated_since=), pour se resynchroniser après une panne.LectureGET/orders/{ref}Lire une commande par la référence de votre boutique : statut, paiement, suivi, totaux, lignes.LecturePOST/orders/{ref}/statusSignaler un changement : payée, expédiée (avec n° de suivi), annulée, remboursée.Clé lecture et écritureGET/invoicesLister les factures et avoirs émis, modifiés depuis une date (?updated_since=). Jamais les brouillons ; aussi renvoyés avec chaque commande.LectureGET/invoices/{number}/pdfObtenir un lien de téléchargement du PDF d’une facture, valable une heure.LectureGET/openapi.jsonLa description OpenAPI 3.1 de l’API (sans clé).Lecturecurl -X PUT https://hdwcgplfjkofvytvibap.supabase.co/functions/v1/api/v1/customers \
-H "Authorization: Bearer grp_live_xxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"email": "achats@epicerie-du-parc.be",
"name": "Épicerie du Parc",
"company_name": "Épicerie du Parc SRL",
"vat_number": "BE 0412.345.614",
"phone": "+32 81 00 00 00",
"billing_address": { "line1": "Rue du Parc 12", "postal_code": "5000", "city": "Namur", "country": "BE" },
"shipping_address": { "line1": "Rue du Parc 12", "postal_code": "5000", "city": "Namur", "country": "BE" }
}'
201 { "created": true, "customer": { "id": "8f1c…", "email": "achats@epicerie-du-parc.be", … } }curl -X POST https://hdwcgplfjkofvytvibap.supabase.co/functions/v1/api/v1/orders \
-H "Authorization: Bearer grp_live_xxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"external_ref": "SHOP-1001",
"customer": { "email": "achats@epicerie-du-parc.be", "name": "Épicerie du Parc" },
"prices_include_vat": true,
"lines": [
{ "sku": "SOUPE-POTIRON-1L", "quantity": 6, "unit_price": 5.30, "vat_rate": 6 },
{ "sku": "SOUPE-POTIRON-1L-X6", "quantity": 2, "unit_price": 30.00, "vat_rate": 6 }
],
"shipping": { "amount": 6.05, "vat_rate": 21, "method": "bpost" },
"total_incl_vat": 97.85,
"payment_status": "paid"
}'
201 {
"created": true,
"order": { "order_number": "CMD-2026-0412", "external_ref": "SHOP-1001", "status": "confirmed", "total": 97.85, … },
"warnings": []
}Dans cet exemple, le premier SKU est celui du produit (6 pots), le second celui d'une unité de vente (2 cartons de 6).
curl -X POST https://hdwcgplfjkofvytvibap.supabase.co/functions/v1/api/v1/orders/SHOP-1001/status \
-H "Authorization: Bearer grp_live_xxxxxxxx" \
-H "Content-Type: application/json" \
-d '{ "status": "shipped", "tracking_number": "323212345678", "carrier": "bpost" }'
200 { "applied": true, "order": { "status": "shipped", "tracking_number": "323212345678", … }, "messages": [] }external_ref (le numéro de commande de votre boutique) est obligatoire. Renvoyer la même commande rend celle déjà créée, sans la modifier. Côté clients, c'est l'e-mail qui sert de clé.
Grapify garde les prix de votre boutique : envoyez-les hors TVA, ou TVA comprise avec prices_include_vat. Le taux de TVA est obligatoire sur chaque ligne et sur les frais de livraison.
Grapify calcule les totaux comme sur sa facture. Si votre total TTC (total_incl_vat) diffère, la commande est créée quand même et la réponse le signale.
Un SKU peut être la référence d'un produit (quantité en pièces) ou celle d'une unité de vente (quantité en cartons, par exemple). Un SKU inconnu ne bloque rien : la commande arrive en brouillon, à relire dans Grapify.
Confirmée si elle est déjà payée, en attente sinon. Elle se prépare ensuite dans Grapify comme toute commande : lots, préparation, bon de livraison.
Expédiée n'est appliquée que si la commande est prête dans Grapify (lots choisis) ; le n° de suivi est noté dans tous les cas. Une annulation remet le stock sur ses lots. Un remboursement est noté : l'avoir se fait dans Grapify.
Elle est faite par Grapify, avec ses lots, sa comptabilité et l’envoi Peppol pour les clients professionnels. Pour éviter une double facture, désactivez la facturation dans votre boutique pour ces commandes.
Grapify appelle l'adresse de rappel de votre boutique pour les événements que vous cochez : une commande reçue par l'API qui change (statut, paiement, expédition, n° de suivi), le stock disponible qui bouge (toutes les 5 minutes au plus), une facture émise.
Dans la carte API Grapify, bloc « Notifications vers votre boutique ». L'adresse doit commencer par https:// et être publique. Grapify vous montre une seule fois le secret de signature (whsec_…).
Chaque appel porte l'en-tête Grapify-Signature : t (horodatage) et v1 (HMAC-SHA256 de « t.corps » avec votre secret). Refusez un appel dont la signature ne correspond pas ou trop ancien.
Répondez par un code 2xx en moins de 10 secondes. Sinon Grapify réessaie après 1 min, 5 min, 30 min, 2 h, 6 h, 12 h et 24 h. Grapify-Delivery identifie chaque notification : servez-vous-en pour ignorer un doublon.
POST https://shop.example.com/hooks/grapify
Grapify-Event: order.updated
Grapify-Delivery: 5b0e…
Grapify-Signature: t=1793095200,v1=6f2c…
{
"id": "5b0e…",
"event": "order.updated",
"occurred_at": "2026-10-27T10:00:00Z",
"order": {
"order_number": "CMD-2026-0412", "external_ref": "SHOP-1001",
"status": "shipped", "payment_status": "paid", "shipping_status": "shipped",
"tracking_number": "323212345678", "total": 97.85, "currency": "EUR"
},
"previous": { "status": "ready", "payment_status": "paid", "shipping_status": "pending", "tracking_number": null }
}// Node.js: check that a notification really comes from Grapify
import crypto from "node:crypto";
function isFromGrapify(rawBody, signatureHeader, secret) {
const parts = Object.fromEntries(signatureHeader.split(",").map((p) => p.split("=")));
const expected = crypto.createHmac("sha256", secret).update(`${parts.t}.${rawBody}`).digest("hex");
const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300; // 5 minutes
return fresh && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1 ?? ""));
}Les erreurs ont toujours la même forme : un code stable, à tester dans votre programme, et un message en anglais pour la personne qui lit les journaux.
401 {
"error": { "code": "invalid_api_key", "message": "Invalid, revoked or expired API key." }
}120 appels par minute et par clé. Au-delà : erreur 429, réessayez une minute plus tard.
Parlez-nous de votre boutique : nous vous aidons à la relier à Grapify.
