API REST de FenuaCompta : clients, devis, factures, paiements, dépenses et boutique en ligne.
URL de base : https://VOTRE-COMPTE.fenuacompta.com/api/v1
Chaque requête s'authentifie par une clé API, dans l'entête Authorization. Une clé a les droits de l'utilisateur qui l'a créée et reste valable jusqu'à sa révocation.
curl https://VOTRE-COMPTE.fenuacompta.com/api/v1/me \
-H "Authorization: Bearer VOTRE_CLE_API"
const BASE = "https://VOTRE-COMPTE.fenuacompta.com/api/v1";
const token = process.env.FENUACOMPTA_API_KEY; // "fenuacompta_key_..."
const me = await fetch(BASE + "/me", {
headers: { "Authorization": "Bearer " + token }
}).then(r => r.json());
<?php
$base = "https://VOTRE-COMPTE.fenuacompta.com/api/v1";
$key = getenv("FENUACOMPTA_API_KEY"); // "fenuacompta_key_..."
function fenuacompta(string $method, string $path, ?array $body = null): array
{
global $base, $key;
$ch = curl_init($base . $path);
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["Authorization: Bearer $key", "Content-Type: application/json", "Accept: application/json"],
]);
if ($body !== null) {
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body));
}
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
return $response;
}
$me = fenuacompta("GET", "/me");
401).Créer un client, puis un devis ou une facture pour ce client.
Crée la fiche client et son contact. Pour réutiliser un client existant, cherchez-le avec GET /clients?q=.
curl -X POST https://VOTRE-COMPTE.fenuacompta.com/api/v1/clients \
-H "Authorization: Bearer VOTRE_CLE_API" \
-H "Content-Type: application/json" \
-d '{ "name": "Acme Sarl", "email": "contact@example.com", "phone": "+689 00 00 00 00" }'
await fetch(BASE + "/clients", {
method: "POST",
headers: { "Content-Type": "application/json", "Authorization": "Bearer " + token },
body: JSON.stringify({ name: "Acme Sarl", email: "contact@example.com", phone: "+689 00 00 00 00" })
}).then(r => r.json());
$client = fenuacompta("POST", "/clients", [
"name" => "Acme Sarl",
"email" => "contact@example.com",
"phone" => "+689 00 00 00 00",
]);
{ "id": 42, "name": "Acme Sarl", "email": "contact@example.com", "phone": "+689 00 00 00 00" }
POST /clients.clientId est absent.GET /products).title : titre de section, text : paragraphe de texte mis en forme. Leur prix, quantité et TVA sont ignorés."" les retire.422 : Client introuvable, somme des lignes nulle, ou montant supérieur à 99 999 999 F.curl -X POST https://VOTRE-COMPTE.fenuacompta.com/api/v1/estimates \
-H "Authorization: Bearer VOTRE_CLE_API" \
-H "Content-Type: application/json" \
-d '{
"clientId": 42,
"lines": [
{ "description": "Prestation de conseil", "unitPrice": 10000, "quantity": 1, "tvaBucket": "tva16" }
],
"expiryDate": "2026-10-30"
}'
await fetch(BASE + "/estimates", {
method: "POST",
headers: { "Content-Type": "application/json", "Authorization": "Bearer " + token },
body: JSON.stringify({
clientId: 42,
lines: [
{ description: "Prestation de conseil", unitPrice: 10000, quantity: 1, tvaBucket: "tva16" }
],
expiryDate: "2026-10-30"
})
}).then(r => r.json());
$estimate = fenuacompta("POST", "/estimates", [
"clientId" => 42,
"lines" => [
["description" => "Prestation de conseil", "unitPrice" => 10000, "quantity" => 1, "tvaBucket" => "tva16"],
],
"expiryDate" => "2026-10-30",
]);
{ "id": 108, "number": "DEV-108", "clientId": 42, "status": "sent", "subtotal": 10000, "total": 11600 }
Mêmes champs que le devis, avec dueDate (échéance) au lieu de expiryDate.
422 : Client introuvable, somme des lignes nulle, ou montant supérieur à 99 999 999 F.curl -X POST https://VOTRE-COMPTE.fenuacompta.com/api/v1/invoices \
-H "Authorization: Bearer VOTRE_CLE_API" \
-H "Content-Type: application/json" \
-d '{
"clientId": 42,
"lines": [
{ "description": "Prestation de conseil", "unitPrice": 10000, "quantity": 1, "tvaBucket": "tva16" }
],
"dueDate": "2026-10-30"
}'
await fetch(BASE + "/invoices", {
method: "POST",
headers: { "Content-Type": "application/json", "Authorization": "Bearer " + token },
body: JSON.stringify({
clientId: 42,
lines: [
{ description: "Prestation de conseil", unitPrice: 10000, quantity: 1, tvaBucket: "tva16" }
],
dueDate: "2026-10-30"
})
}).then(r => r.json());
$invoice = fenuacompta("POST", "/invoices", [
"clientId" => 42,
"lines" => [
["description" => "Prestation de conseil", "unitPrice" => 10000, "quantity" => 1, "tvaBucket" => "tva16"],
],
"dueDate" => "2026-10-30",
]);
La boutique lit le catalogue et le stock de FenuaCompta, puis y envoie ses commandes : chacune devient une facture et décrémente le stock. Les produits sont reliés par leur référence (SKU).
Les produits du catalogue avec leur prix, leur stock, leur catégorie, leurs descriptions et leurs images. Une synchronisation régulière ne demande que les produits modifiés depuis la précédente.
1 : seulement les produits qui ont une référence, c'est-à-dire ceux vendus en ligne.stock et lowStockAlert valent null si le stock n'est pas suivi. Le stock est en unités entières. priceTtc est arrondi à la précision du compte (franc, ou centime pour un compte à 2 décimales).priceTtc → regular_price, shortDescription → short_description, category.name → categories, images[].url → images[].src, stock → stock_quantity. Les URL d'images sont publiques.403 : Module boutique non activé sur ce compte (module_disabled).curl "https://VOTRE-COMPTE.fenuacompta.com/api/v1/shop/products?hasSku=1&updatedSince=2026-09-23T08:00:00-10:00" \
-H "Authorization: Bearer VOTRE_CLE_API"
const { data } = await fetch(BASE + "/shop/products?hasSku=1&updatedSince=" + encodeURIComponent(lastSync), {
headers: { "Authorization": "Bearer " + token }
}).then(r => r.json());
$page = fenuacompta("GET", "/shop/products?hasSku=1&updatedSince=" . urlencode($lastSync));
foreach ($page["data"] as $product) {
// créer ou mettre à jour le produit de la boutique ayant ce SKU
}
{
"data": [
{ "id": 12, "sku": "MIEL-500", "name": "Miel de Tahiti 500 g", "unit": "pot",
"category": { "id": 14, "name": "Épicerie fine" },
"shortDescription": "Miel de fleurs récolté à Taravao.",
"description": "<p>Miel cru, non chauffé, mis en pot à la main.</p>",
"images": [
{ "id": 301, "url": "https://VOTRE-COMPTE.fenuacompta.com/…/miel-500.jpg",
"thumbnailUrl": "https://VOTRE-COMPTE.fenuacompta.com/…/miel-500-thumb.jpg", "name": "miel-500.jpg", "position": 0 }
],
"priceHt": 1500, "tvaRate": 5, "priceTtc": 1575,
"stockManaged": true, "stock": 42, "lowStockAlert": 5,
"updatedAt": "2026-09-23T09:14:02-10:00" }
],
"page": 1, "perPage": 100, "total": 1
}
Retrouve ou crée le client (par email), crée la facture au prix payé et, si la commande est payée, le paiement. Le stock est décrémenté.
reference, identifie la commande.paid : la facture est soldée. pending : elle reste due, à payer plus tard avec POST /shop/orders/{reference}/payment.totals.stock, le stock à jour des produits de la commande dont le stock est suivi. Reportez-le dans la boutique, qui décrémente aussi son propre stock.200 et "duplicate": true : un envoi peut être rejoué sans risque.paymentRecorded indique si le paiement a été enregistré. S'il vaut false, enregistrez-le avec POST /shop/orders/{reference}/payment.403 : Module boutique non activé sur ce compte (module_disabled).422 : Référence de produit inconnue, quantité non entière pour un produit dont le stock est suivi, total nul ou taux de TVA des frais manquant : rien n'est créé.409 : Opération impossible dans l'état actuel de la commande : réessayez plus tard ou consultez GET /shop/orders/{reference}.curl -X POST https://VOTRE-COMPTE.fenuacompta.com/api/v1/shop/orders \
-H "Authorization: Bearer VOTRE_CLE_API" \
-H "Content-Type: application/json" \
-d '{
"reference": "1042",
"customer": { "email": "client@example.com", "firstName": "Teva", "lastName": "Exemple",
"phone": "+689 00 00 00 00", "address": { "street": "Rue du Commerce", "city": "Papeete", "zip": "98714" } },
"lines": [ { "sku": "MIEL-500", "quantity": 2, "unitPriceTtc": 1575 } ],
"shipping": { "label": "Livraison Tahiti", "amountTtc": 1000, "tvaRate": 13 },
"payment": { "status": "paid", "method": "Carte bancaire", "transactionId": "pi_3Q..." },
"totalTtc": 4150
}'
const order = await fetch(BASE + "/shop/orders", {
method: "POST",
headers: { "Content-Type": "application/json", "Authorization": "Bearer " + token },
body: JSON.stringify({
reference: String(wcOrder.id),
customer: { email: wcOrder.billing.email, firstName: wcOrder.billing.first_name, lastName: wcOrder.billing.last_name },
lines: wcOrder.line_items.map(l => ({ sku: l.sku, quantity: l.quantity, unitPriceTtc: (Number(l.total) + Number(l.total_tax)) / l.quantity })),
shipping: { amountTtc: Number(wcOrder.shipping_total) + Number(wcOrder.shipping_tax), tvaRate: 13 }, // taux de vos frais de livraison
payment: { status: wcOrder.date_paid ? "paid" : "pending", method: (wcOrder.payment_method_title || "").slice(0, 60) },
totalTtc: Number(wcOrder.total)
})
}).then(r => r.json());
// $wcOrder : la commande WooCommerce (JSON de son API REST, décodé)
$order = fenuacompta("POST", "/shop/orders", [
"reference" => (string) $wcOrder["id"],
"customer" => [
"email" => $wcOrder["billing"]["email"],
"firstName" => $wcOrder["billing"]["first_name"],
"lastName" => $wcOrder["billing"]["last_name"],
],
"lines" => array_map(fn ($l) => [
"sku" => $l["sku"],
"quantity" => $l["quantity"],
"unitPriceTtc" => ($l["total"] + $l["total_tax"]) / $l["quantity"],
], $wcOrder["line_items"]),
"shipping" => [
"amountTtc" => $wcOrder["shipping_total"] + $wcOrder["shipping_tax"],
"tvaRate" => 13, // taux de vos frais de livraison
],
"payment" => [
"status" => $wcOrder["date_paid"] ? "paid" : "pending",
"method" => mb_substr((string) $wcOrder["payment_method_title"], 0, 60),
],
"totalTtc" => (float) $wcOrder["total"],
]);
{
"source": "woocommerce", "reference": "1042", "status": "invoiced", "clientId": 57,
"invoice": { "id": 318, "number": "FACT-318", "status": "paid", "total": 4150, ... },
"creditNote": null,
"totals": { "invoice": 4150, "site": 4150, "difference": 0 },
"stock": [ { "sku": "MIEL-500", "stock": 40 } ],
"paymentRecorded": true
}
method, transactionId, date optionnelsToutes les routes, par ressource. Cliquez sur une route pour voir ses champs et sa réponse.
/me
Vérifier la clé
L'utilisateur de la clé et le compte. Le bon appel pour tester une clé.
{
"user": {
"id": 1,
"firstName": "Teva",
"lastName": "Exemple",
"email": "client@example.com",
"role": "Administrateur"
},
"account": {
"name": "Ma société",
"tvaEnabled": true,
"decimals": 0
}
}
/clients
Lister les clients
Les clients actifs, par ordre alphabétique (1 000 au plus).
{
"data": [
{
"id": 42,
"name": "Acme Sarl",
"email": "contact@example.com",
"outstanding": 0,
"dueCount": 0,
"invoiceCount": 1,
"totalBilled": 11600
}
]
}
/clients
Créer un client
Crée la fiche client et son contact. Pour réutiliser un client existant, cherchez-le avec GET /clients?q=.
{
"id": 42,
"name": "Acme Sarl",
"email": "contact@example.com",
"phone": "+689 00 00 00 00"
}
/clients/{id}
Détail d'un client
La fiche, le reste dû, et l'historique des factures, devis et paiements.
404 : Client introuvable.{
"id": 42,
"name": "Acme Sarl",
"email": "contact@example.com",
"phone": "+689 00 00 00 00",
"website": null,
"vat": null,
"city": "Papeete",
"zip": "98714",
"country": null,
"outstanding": 0,
"invoices": [
{
"id": 318,
"number": "FACT-318",
"date": "2026-09-23",
"total": 11600,
"status": "paid"
}
],
"estimates": [
{
"id": 108,
"number": "DEV-108",
"date": "2026-09-20",
"total": 11600,
"status": "accepted"
}
],
"payments": [
{
"id": 77,
"date": "2026-09-23",
"amount": 11600,
"method": "Virement",
"invoiceNumber": "FACT-318"
}
]
}
/clients/{id}
Modifier un client
Seuls les champs envoyés changent ; un champ envoyé à null est effacé.
404 : Client introuvable.422 : L'email n'a pas pu être enregistré pour ce client.{
"id": 42,
"name": "Acme Sarl",
"email": "contact@example.com",
"phone": "+689 00 00 00 00",
"website": null,
"vat": null,
"city": "Papeete",
"zip": "98714",
"country": null,
"outstanding": 0,
"invoices": [
{
"id": 318,
"number": "FACT-318",
"date": "2026-09-23",
"total": 11600,
"status": "paid"
}
],
"estimates": [
{
"id": 108,
"number": "DEV-108",
"date": "2026-09-20",
"total": 11600,
"status": "accepted"
}
],
"payments": [
{
"id": 77,
"date": "2026-09-23",
"amount": 11600,
"method": "Virement",
"invoiceNumber": "FACT-318"
}
]
}
/estimates
Lister les devis
Les devis, du plus récent au plus ancien (1 000 au plus), sans leurs lignes.
draft, sent, accepted, declined, revised, expired.{
"data": [
{
"id": 108,
"number": "DEV-108",
"clientId": 42,
"clientName": "Acme Sarl",
"title": "",
"status": "sent",
"subtotal": 10000,
"discount": {
"type": null,
"percentage": 0,
"amount": 0
},
"tvaTotal": 1600,
"total": 11600,
"createdAt": "2026-09-28T08:16:30-10:00",
"date": "2026-09-28",
"expiryDate": "2026-10-28",
"lines": []
}
]
}
/estimates
Créer un devis
POST /clients.clientId est absent.GET /products).title : titre de section, text : paragraphe de texte mis en forme. Leur prix, quantité et TVA sont ignorés."" les retire.422 : Client introuvable, somme des lignes nulle, ou montant supérieur à 99 999 999 F.{
"id": 108,
"number": "DEV-108",
"clientId": 42,
"clientName": "Acme Sarl",
"title": "",
"status": "sent",
"subtotal": 10000,
"discount": {
"type": null,
"percentage": 0,
"amount": 0
},
"tvaTotal": 1600,
"total": 11600,
"createdAt": "2026-09-28T08:16:30-10:00",
"date": "2026-09-28",
"expiryDate": "2026-10-28",
"lines": [
{
"id": 19,
"productId": null,
"description": "Prestation de conseil",
"unitPrice": 10000,
"unitPriceExact": 10000,
"quantity": 1,
"unit": "u",
"tvaBucket": "tva16",
"lineTotal": 10000
}
],
"tvaBreakdown": [
{
"key": "tva16",
"label": "TVA 16 %",
"rate": 16,
"amount": 1600
}
],
"terms": "<p>Mauruuru pour votre confiance.</p>",
"hasSections": false,
"emails": []
}
/estimates/{id}
Détail d'un devis
Le devis avec ses lignes, le détail de la TVA et les emails envoyés.
1 : inclut aussi les lignes de titre et de texte.404 : Devis introuvable.{
"id": 108,
"number": "DEV-108",
"clientId": 42,
"clientName": "Acme Sarl",
"title": "",
"status": "sent",
"subtotal": 10000,
"discount": {
"type": null,
"percentage": 0,
"amount": 0
},
"tvaTotal": 1600,
"total": 11600,
"createdAt": "2026-09-28T08:16:30-10:00",
"date": "2026-09-28",
"expiryDate": "2026-10-28",
"lines": [
{
"id": 19,
"productId": null,
"description": "Prestation de conseil",
"unitPrice": 10000,
"unitPriceExact": 10000,
"quantity": 1,
"unit": "u",
"tvaBucket": "tva16",
"lineTotal": 10000
}
],
"tvaBreakdown": [
{
"key": "tva16",
"label": "TVA 16 %",
"rate": 16,
"amount": 1600
}
],
"terms": "<p>Mauruuru pour votre confiance.</p>",
"hasSections": false,
"emails": []
}
/estimates/{id}/pdf
Télécharger le PDF
Le devis en PDF (application/pdf), tel que l'imprime le logiciel.
404 : Devis introuvable.Fichier application/pdf.
/estimates/{id}/send
Envoyer par email
Envoie le devis en PDF à l'email du client. Le statut du devis ne change pas.
404 : Devis introuvable.422 : Le client n'a pas d'email (no_recipient).{
"ok": true,
"status": "sent"
}
/estimates/{id}/convert
Convertir en facture
Crée la facture du devis, datée du jour ; le devis est conservé. Si le devis a déjà été converti, renvoie la même facture (200).
404 : Devis introuvable.{
"id": 319,
"number": "FACT-319"
}
{
"id": 319,
"number": "FACT-319"
}
/invoices
Lister les factures
Les factures, de la plus récente à la plus ancienne (1 000 au plus), avec le payé et le reste dû.
draft, due, overdue, part_paid, paid, credit (avoir).{
"data": [
{
"id": 318,
"number": "FACT-318",
"clientId": 42,
"clientName": "Acme Sarl",
"title": "",
"status": "due",
"subtotal": 10000,
"discount": {
"type": null,
"percentage": 0,
"amount": 0
},
"tvaTotal": 1600,
"total": 11600,
"createdAt": "2026-09-28T08:16:30-10:00",
"date": "2026-09-28",
"dueDate": "2026-10-28",
"lines": [],
"paid": 0,
"balance": 11600
}
]
}
/invoices
Créer une facture
POST /clients.clientId est absent.GET /products).title : titre de section, text : paragraphe de texte mis en forme. Leur prix, quantité et TVA sont ignorés."" les retire.422 : Client introuvable, somme des lignes nulle, ou montant supérieur à 99 999 999 F.{
"id": 318,
"number": "FACT-318",
"clientId": 42,
"clientName": "Acme Sarl",
"title": "",
"status": "due",
"subtotal": 10000,
"discount": {
"type": null,
"percentage": 0,
"amount": 0
},
"tvaTotal": 1600,
"total": 11600,
"createdAt": "2026-09-28T08:16:30-10:00",
"date": "2026-09-28",
"dueDate": "2026-10-28",
"lines": [
{
"id": 19,
"productId": null,
"description": "Prestation de conseil",
"unitPrice": 10000,
"unitPriceExact": 10000,
"quantity": 1,
"unit": "u",
"tvaBucket": "tva16",
"lineTotal": 10000
}
],
"tvaBreakdown": [
{
"key": "tva16",
"label": "TVA 16 %",
"rate": 16,
"amount": 1600
}
],
"terms": "<p>Mauruuru pour votre confiance.</p>",
"hasSections": false,
"payments": [],
"paid": 0,
"balance": 11600,
"emails": []
}
/invoices/{id}
Détail d'une facture
La facture avec ses lignes, le détail de la TVA, les paiements et les emails envoyés.
1 : inclut aussi les lignes de titre et de texte.404 : Facture introuvable.{
"id": 318,
"number": "FACT-318",
"clientId": 42,
"clientName": "Acme Sarl",
"title": "",
"status": "due",
"subtotal": 10000,
"discount": {
"type": null,
"percentage": 0,
"amount": 0
},
"tvaTotal": 1600,
"total": 11600,
"createdAt": "2026-09-28T08:16:30-10:00",
"date": "2026-09-28",
"dueDate": "2026-10-28",
"lines": [
{
"id": 19,
"productId": null,
"description": "Prestation de conseil",
"unitPrice": 10000,
"unitPriceExact": 10000,
"quantity": 1,
"unit": "u",
"tvaBucket": "tva16",
"lineTotal": 10000
}
],
"tvaBreakdown": [
{
"key": "tva16",
"label": "TVA 16 %",
"rate": 16,
"amount": 1600
}
],
"terms": "<p>Mauruuru pour votre confiance.</p>",
"hasSections": false,
"payments": [],
"paid": 0,
"balance": 11600,
"emails": []
}
/invoices/{id}/pdf
Télécharger le PDF
La facture en PDF (application/pdf).
404 : Facture introuvable.Fichier application/pdf.
/invoices/{id}/send
Envoyer par email
Envoie la facture en PDF à l'email du client.
404 : Facture introuvable.422 : Le client n'a pas d'email (no_recipient).{
"ok": true,
"status": "due"
}
/payments
Enregistrer un paiement
Un paiement reçu sur une facture ; son statut est recalculé (payée, partiellement payée).
status : le statut de la facture après le paiement (paid, part_paid...).404 : Facture introuvable.{
"ok": true,
"invoiceId": 318,
"status": "paid"
}
/expenses
Lister les dépenses
Les dépenses créées par l'utilisateur de la clé, de la plus récente à la plus ancienne (1 000 au plus).
{
"data": [
{
"id": 55,
"amount": 11600,
"tva": {
"tva16": 1600
},
"importTva": null,
"title": "Fournitures de bureau",
"supplierId": null,
"supplierName": null,
"categoryId": 3,
"clientId": null,
"date": "2026-09-20",
"paymentStatus": "paid",
"paymentMethod": "Carte bancaire",
"paymentDate": "2026-09-20",
"dueDate": null,
"notes": null,
"attachmentId": null,
"attachmentUrl": null,
"attachmentType": null,
"attachmentName": null,
"createdAt": "2026-09-20T10:02:11-10:00"
}
]
}
/expenses
Créer une dépense
pending : dépense à payer, avec dueDate.{
"id": 55,
"amount": 11600,
"tva": {
"tva16": 1600
},
"importTva": null,
"title": "Fournitures de bureau",
"supplierId": null,
"supplierName": null,
"categoryId": 3,
"clientId": null,
"date": "2026-09-20",
"paymentStatus": "paid",
"paymentMethod": "Carte bancaire",
"paymentDate": "2026-09-20",
"dueDate": null,
"notes": null,
"attachmentId": null,
"attachmentUrl": null,
"attachmentType": null,
"attachmentName": null,
"createdAt": "2026-09-20T10:02:11-10:00"
}
/products
Lister les produits
Le catalogue, par ordre alphabétique (200 au plus) : de quoi remplir des lignes de devis ou de facture.
{
"data": [
{
"id": 12,
"name": "Miel de Tahiti 500 g",
"unitPrice": 1500,
"unitPriceExact": 1500,
"tvaBucket": "tva5",
"unit": "pot",
"kind": "produit"
}
]
}
/products
Créer un produit
{
"id": 12,
"name": "Miel de Tahiti 500 g",
"unitPrice": 1500,
"unitPriceExact": 1500,
"tvaBucket": "tva5",
"unit": "pot",
"kind": "produit"
}
/products/{id}
Modifier un produit
Seuls les champs envoyés changent. Cette route ne modifie pas le stock.
404 : Produit introuvable.422 : Aucun champ à modifier.{
"id": 12,
"name": "Miel de Tahiti 500 g",
"unitPrice": 1500,
"unitPriceExact": 1500,
"tvaBucket": "tva5",
"unit": "pot",
"kind": "produit"
}
/products/{id}
Supprimer un produit
Supprime le produit et ses images. Les factures déjà émises gardent leurs lignes.
404 : Produit introuvable.{
"ok": true
}
/shop/products
Lire le catalogue et le stock
Les produits du catalogue avec leur prix, leur stock, leur catégorie, leurs descriptions et leurs images. Une synchronisation régulière ne demande que les produits modifiés depuis la précédente.
1 : seulement les produits qui ont une référence, c'est-à-dire ceux vendus en ligne.stock et lowStockAlert valent null si le stock n'est pas suivi. Le stock est en unités entières. priceTtc est arrondi à la précision du compte (franc, ou centime pour un compte à 2 décimales).priceTtc → regular_price, shortDescription → short_description, category.name → categories, images[].url → images[].src, stock → stock_quantity. Les URL d'images sont publiques.403 : Module boutique non activé sur ce compte (module_disabled).{
"data": [
{
"id": 12,
"sku": "MIEL-500",
"name": "Miel de Tahiti 500 g",
"unit": "pot",
"category": {
"id": 14,
"name": "Épicerie fine"
},
"shortDescription": "Miel de fleurs récolté à Taravao.",
"description": "<p>Miel cru, non chauffé, mis en pot à la main.</p>",
"images": [
{
"id": 301,
"url": "https://VOTRE-COMPTE.fenuacompta.com/…/miel-500.jpg",
"thumbnailUrl": "https://VOTRE-COMPTE.fenuacompta.com/…/miel-500-thumb.jpg",
"name": "miel-500.jpg",
"position": 0
}
],
"priceHt": 1500,
"tvaRate": 5,
"priceTtc": 1575,
"stockManaged": true,
"stock": 42,
"lowStockAlert": 5,
"updatedAt": "2026-09-23T09:14:02-10:00"
}
],
"page": 1,
"perPage": 100,
"total": 1
}
/shop/orders
Facturer une commande de la boutique
Retrouve ou crée le client (par email), crée la facture au prix payé et, si la commande est payée, le paiement. Le stock est décrémenté.
reference, identifie la commande.paid : la facture est soldée. pending : elle reste due, à payer plus tard avec POST /shop/orders/{reference}/payment.totals.stock, le stock à jour des produits de la commande dont le stock est suivi. Reportez-le dans la boutique, qui décrémente aussi son propre stock.200 et "duplicate": true : un envoi peut être rejoué sans risque.paymentRecorded indique si le paiement a été enregistré. S'il vaut false, enregistrez-le avec POST /shop/orders/{reference}/payment.403 : Module boutique non activé sur ce compte (module_disabled).422 : Référence de produit inconnue, quantité non entière pour un produit dont le stock est suivi, total nul ou taux de TVA des frais manquant : rien n'est créé.409 : Opération impossible dans l'état actuel de la commande : réessayez plus tard ou consultez GET /shop/orders/{reference}.{
"source": "woocommerce",
"reference": "1042",
"status": "invoiced",
"clientId": 57,
"invoice": {
"id": 318,
"number": "FACT-318",
"clientId": 57,
"clientName": "Teva Exemple",
"title": "Commande en ligne n° 1042",
"status": "paid",
"subtotal": 3634,
"discount": {
"type": null,
"percentage": 0,
"amount": 0
},
"tvaTotal": 516,
"total": 4150,
"createdAt": "2026-09-23T09:20:11-10:00",
"date": "2026-09-23",
"dueDate": "2026-09-23",
"lines": []
},
"creditNote": null,
"totals": {
"invoice": 4150,
"site": 4150,
"difference": 0
},
"stock": [
{
"sku": "MIEL-500",
"stock": 40
}
],
"paymentRecorded": true
}
{
"source": "woocommerce",
"reference": "1042",
"status": "invoiced",
"clientId": 57,
"invoice": {
"id": 318,
"number": "FACT-318",
"clientId": 57,
"clientName": "Teva Exemple",
"title": "Commande en ligne n° 1042",
"status": "paid",
"subtotal": 3634,
"discount": {
"type": null,
"percentage": 0,
"amount": 0
},
"tvaTotal": 516,
"total": 4150,
"createdAt": "2026-09-23T09:20:11-10:00",
"date": "2026-09-23",
"dueDate": "2026-09-23",
"lines": []
},
"creditNote": null,
"totals": {
"invoice": 4150,
"site": 4150,
"difference": 0
},
"stock": [
{
"sku": "MIEL-500",
"stock": 40
}
],
"duplicate": true
}
/shop/orders/{reference}
État d'une commande facturée
La commande, sa facture et, si elle a été annulée, son avoir.
source.404 : Aucune commande avec cette référence (et cette source).403 : Module boutique non activé sur ce compte (module_disabled).{
"source": "woocommerce",
"reference": "1042",
"status": "invoiced",
"clientId": 57,
"invoice": {
"id": 318,
"number": "FACT-318",
"clientId": 57,
"clientName": "Teva Exemple",
"title": "Commande en ligne n° 1042",
"status": "paid",
"subtotal": 3634,
"discount": {
"type": null,
"percentage": 0,
"amount": 0
},
"tvaTotal": 516,
"total": 4150,
"createdAt": "2026-09-23T09:20:11-10:00",
"date": "2026-09-23",
"dueDate": "2026-09-23",
"lines": []
},
"creditNote": null,
"totals": {
"invoice": 4150,
"site": 4150,
"difference": 0
}
}
/shop/orders/{reference}/cancel
Annuler une commande
Annulation totale : crée un avoir et remet le stock. Le remboursement se fait dans votre moyen de paiement. Une commande déjà annulée renvoie la même réponse, sans second avoir.
source.404 : Aucune commande avec cette référence (et cette source).403 : Module boutique non activé sur ce compte (module_disabled).409 : Opération impossible dans l'état actuel de la commande : réessayez plus tard ou consultez GET /shop/orders/{reference}.{
"source": "woocommerce",
"reference": "1042",
"status": "cancelled",
"clientId": 57,
"invoice": {
"id": 318,
"number": "FACT-318",
"clientId": 57,
"clientName": "Teva Exemple",
"title": "Commande en ligne n° 1042",
"status": "paid",
"subtotal": 3634,
"discount": {
"type": null,
"percentage": 0,
"amount": 0
},
"tvaTotal": 516,
"total": 4150,
"createdAt": "2026-09-23T09:20:11-10:00",
"date": "2026-09-23",
"dueDate": "2026-09-23",
"lines": []
},
"creditNote": {
"id": 325,
"number": "FACT-325",
"clientId": 57,
"clientName": "Teva Exemple",
"title": "Commande en ligne n° 1042",
"status": "credit",
"subtotal": -3634,
"discount": {
"type": null,
"percentage": 0,
"amount": 0
},
"tvaTotal": -516,
"total": -4150,
"createdAt": "2026-09-24T08:02:40-10:00",
"date": "2026-09-24",
"dueDate": "2026-09-24",
"lines": []
},
"totals": {
"invoice": 4150,
"site": 4150,
"difference": 0
},
"stock": [
{
"sku": "MIEL-500",
"stock": 42
}
]
}
/shop/orders/{reference}/payment
Enregistrer le paiement d'une commande
Pour une commande envoyée en pending puis payée sur la boutique : enregistre le paiement du reste dû. Une facture déjà soldée n'est pas payée deux fois.
source.404 : Aucune commande avec cette référence (et cette source).403 : Module boutique non activé sur ce compte (module_disabled).409 : Opération impossible dans l'état actuel de la commande : réessayez plus tard ou consultez GET /shop/orders/{reference}.{
"source": "woocommerce",
"reference": "1042",
"status": "invoiced",
"clientId": 57,
"invoice": {
"id": 318,
"number": "FACT-318",
"clientId": 57,
"clientName": "Teva Exemple",
"title": "Commande en ligne n° 1042",
"status": "paid",
"subtotal": 3634,
"discount": {
"type": null,
"percentage": 0,
"amount": 0
},
"tvaTotal": 516,
"total": 4150,
"createdAt": "2026-09-23T09:20:11-10:00",
"date": "2026-09-23",
"dueDate": "2026-09-23",
"lines": []
},
"creditNote": null,
"totals": {
"invoice": 4150,
"site": 4150,
"difference": 0
},
"stock": [
{
"sku": "MIEL-500",
"stock": 40
}
],
"paymentRecorded": true
}
| Sujet | Règle |
|---|---|
| Format | JSON en entrée et en sortie. Dates AAAA-MM-JJ. Les listes renvoient leurs éléments dans data, sans pagination (sauf le catalogue de la boutique) : 1 000 au plus, 200 pour les produits. |
| Montants | En XPF. Devis et factures : prix HT par ligne. Taux dans tvaBucket : tva16, tva13, tva5, tva1, tva0. Commandes de la boutique : prix TTC payés. |
| Commandes | Identifiées par source + reference : renvoyer une commande ne crée pas de doublon. |
| Limite | 90 requêtes par minute. Au-delà : 429. |
Erreurs. Le corps de la réponse est { code, message, fields }.
| Statut | Signification |
|---|---|
401 | Clé absente, invalide ou révoquée |
402 | Abonnement inactif |
403 | Permission insuffisante ou module non activé |
404 | Ressource introuvable |
409 | Opération impossible dans l'état actuel |
422 | Données invalides, détail dans fields |
429 | Trop de requêtes |