Développeurs
Récupérez en lecture seule, au format JSON, les commandes en cours, les statistiques de ventes, le catalogue d'articles et le stock d'un établissement. Pratique pour alimenter un écran cuisine, un tableau de bord, un outil comptable ou une application tierce.
GET, réponses JSON (toujours un tableau), encodage UTF-8.
Remplacez votre-domaine.arpelin.fr par le domaine de l'établissement.
Les points d'accès sont publics : aucun en-tête ni jeton n'est nécessaire.
adresse (mode détaillé) n'est renvoyé en clair que si la requête
porte un cookie de session du backoffice appartenant à un compte de rôle
admin, manager ou cashier. Sinon il est masqué :
seuls le code postal et la ville sont conservés
(exemple : ••• 75011 Paris), ou ••• si aucun code postal
n'est détecté. Depuis un navigateur déjà connecté, envoyez la requête avec
credentials: 'include'.
AAAA-MM-JJ HH:MM:SS (fuseau du serveur).etat est renvoyé sous forme de chaîne JSON : comparez avec == ou convertissez en nombre.En cas d'échec, le code HTTP passe à 500 et le corps devient un objet :
{ "error": "Erreur lors de l'exécution de la requête : ..." }
Le paramètre update sélectionne le mode de réponse :
| Paramètre | Valeur | Effet |
|---|---|---|
update |
absent | Mode synthétique : une entrée par commande, pour affichage TV. |
update |
présent (ex. update=1) |
Mode détaillé : contenu du panier, total, adresse. |
GET /panel/api_gestion
Commandes dont l'horodatage debut est compris entre 12 h avant
et 3 h après l'instant courant, avec un état actif
(0.5 à 2). Livraisons terminées exclues. Une entrée par commande.
| Champ | Type | Description |
|---|---|---|
prep | entier | Numéro de préparation affiché au client. |
etat | nombre | État de la commande (voir Codes d'état). |
debut | datetime | Date et heure de création de la commande. |
retrait | chaîne | Mode de retrait (sur place, a emporter, livraison…). |
note | chaîne | null | Note libre. Peut contenir un marqueur [Nom: …]. |
file_attente | objet | null | Position dans la file et estimation d'attente. Présent uniquement si le module Temps de préparation est actif ; null sinon ou si la commande n'a pas de numéro de préparation. Voir File d'attente. |
[
{ "prep": 42, "etat": "1", "debut": "2026-09-09 12:04:11", "retrait": "sur place", "note": null,
"file_attente": { "position": 0, "message": "C'est bientôt votre tour", "duree_preparation_min": 6, "duree_estimee_min": 6 } },
{ "prep": 43, "etat": "0.6", "debut": "2026-09-09 12:06:52", "retrait": "livraison", "note": "[Nom: Dupont] sans oignon",
"file_attente": { "position": 0, "message": "Commande prête", "duree_preparation_min": 12, "duree_estimee_min": 0 } }
]
Sans le module Temps de préparation, la réponse est identique mais sans la clé file_attente.
GET /panel/api_gestion?update=1
Commandes du jour et de la veille (DATE(debut) ≥ hier) avec un état actif,
livraisons terminées exclues. Une entrée par commande, avec le détail des articles.
| Champ | Type | Description |
|---|---|---|
panier_id | entier | Identifiant de la commande. |
prep | entier | Numéro de préparation. |
etat | nombre | État de la commande (voir Codes d'état). |
heure | datetime | Date et heure de création. |
retrait | chaîne | Mode de retrait. |
total | nombre | Montant total dû en euros (toutes lignes incluses, ventilation TVA comprise). |
note | chaîne | null | Note libre de la commande. |
adresse | chaîne | Adresse de livraison. Masquée hors session staff (voir Authentification). Chaîne vide si retrait sur place ou à emporter. |
commandes | tableau | Articles de la commande (un objet par article, voir ci-dessous). |
file_attente | objet | null | Position dans la file et estimation d'attente. Présent uniquement si le module Temps de préparation est actif ; null sinon ou si la commande n'a pas de numéro de préparation. Voir File d'attente. |
commandes[]| Champ | Type | Description |
|---|---|---|
nom_article | chaîne | Libellé de l'article. |
infos_article | chaîne | null | Personnalisations et options. |
quantite | entier | Quantité commandée. |
prix_article | nombre | Prix unitaire complet en euros (ventilation TVA recomposée). |
[
{
"panier_id": 10432,
"heure": "2026-09-09 12:06:52",
"retrait": "livraison",
"total": 24.5,
"commandes": [
{ "nom_article": "Burger maison", "infos_article": "sans oignon", "quantite": 2, "prix_article": 9.5 },
{ "nom_article": "Frites", "infos_article": null, "quantite": 1, "prix_article": 3.5 },
{ "nom_article": "Coca 33cl", "infos_article": null, "quantite": 1, "prix_article": 2.0 }
],
"note": "[Nom: Dupont] 3e étage",
"adresse": "••• 75011 Paris",
"etat": "1",
"prep": 43,
"file_attente": {
"position": 2,
"message": "2 commandes avant vous",
"duree_preparation_min": 25,
"duree_estimee_min": 43
}
}
]
file_attente
Ajouté à chaque commande des deux modes quand le module Temps de préparation
est actif sur l'établissement (menu Modules → File d'attente du backoffice).
Sans ce module, la clé est absente. Elle vaut null pour une commande sans numéro
de préparation exploitable.
| Champ | Type | Description |
|---|---|---|
position | entier | Nombre de commandes du même jour qui précèdent celle-ci dans la file et ne sont pas encore prêtes. 0 = c'est la prochaine (ou la commande est déjà prête). |
message | chaîne | Formulation prête à afficher : C'est bientôt votre tour, 1 commande avant vous, N commandes avant vous, ou Commande prête (état 0.6 / 2). |
duree_preparation_min | entier | null | Durée de préparation propre à cette commande, en minutes (somme des durées configurées par article × quantité). null si aucun de ses articles n'a de durée configurée. |
duree_estimee_min | entier | null | Estimation du temps d'attente restant avant que cette commande soit prête, en minutes : somme des duree_preparation_min des commandes qui la précèdent et ne sont pas prêtes, plus la sienne. 0 si la commande est déjà prête. null si une des durées nécessaires n'est pas configurée. |
−12 h / +3 h en mode synthétique, jour + veille en
mode détaillé) et sur le même jour que la commande concernée, le numéro de
préparation étant remis à 1 chaque jour. Les durées viennent de la configuration
par article du module ; elles ne tiennent pas compte du nombre de postes de préparation.
etat)| Valeur | Signification |
|---|---|
0.5 | À encaisser |
0.6 | Prête à encaisser |
1 | En cours de préparation |
2 | Prête (à remettre au client) |
Les points d'accès /api/v1/stats, /api/v1/articles et
/api/v1/stock sont privés : chaque appel doit porter une clé secrète,
en lecture seule.
/panel/config?config=advanced), section API : clés secrètes.stats, articles, stock) puis cliquez sur Créer une clé.Dans l'en-tête de chaque requête, jamais dans l'URL :
Authorization: Bearer arp_votre_cle_secrete
# ou
X-API-Key: arp_votre_cle_secrete
Chaque clé ne donne accès qu'aux données de son établissement et aux seuls accès cochés
à sa création. Toutes les requêtes sont en GET. Ne placez jamais une clé dans une page web publique
ou une application distribuée : appelez l'API depuis un programme dont vous maîtrisez l'hébergement.
GET /api/v1/stats
Accès requis : stats. Renvoie les mêmes chiffres que la page Statistiques du backoffice :
chiffre d'affaires, transactions, paiements, ventes par heure et par jour de la semaine, classement des articles,
rentabilité et personnel. Les paniers annulés sont exclus.
| Paramètre | Défaut | Description |
|---|---|---|
start_date | il y a 30 jours | Début de période, AAAA-MM-JJ. |
end_date | aujourd'hui | Fin de période incluse, AAAA-MM-JJ. Durée maximale : 731 jours. |
start_time | 00:00 | Heure de début le premier jour, HH:MM. |
end_time | 23:59 | Heure de fin le dernier jour, HH:MM. |
granularity | automatique | day, week ou month : pas de la courbe d'évolution du chiffre d'affaires. Par défaut : jour jusqu'à 30 jours, semaine jusqu'à 90 jours, mois au-delà. |
top | 20 | Nombre d'articles dans top_articles (1 à 1000). |
include | tout | Liste de sections séparées par des virgules, pour alléger la réponse : summary, sales, payments, hourly, weekly, top_articles, articles, profitability, staff. |
pointages | 0 | Avec 1, la masse salariale (staff) suit les horaires pointés au lieu du planning prévu. |
| Clé | Contenu |
|---|---|
period | Période calculée (start, end) et pas retenu (granularity). |
summary | Chiffre d'affaires TTC (revenue), nombre de commandes (transactions), articles vendus (items_sold), panier moyen, prix moyen par article, meilleure période et évolution en % par rapport à la période précédente de même durée (change_vs_previous_period_pct). |
sales_over_time | Chiffre d'affaires par période : period (2026-09-09, 2026-09 ou 2026-37 pour une semaine) et revenue. |
payments | Montant par moyen de paiement (method, amount). |
sales_by_hour | Chiffre d'affaires pour chacune des 24 heures (hour de 0 à 23). |
sales_by_weekday | Chiffre d'affaires par jour de la semaine (monday à sunday). |
top_articles | Articles les plus vendus : name, quantity, revenue. |
articles | Classement complet des articles vendus, avec average_price. |
profitability | Marge par article d'après les coûts de revient renseignés : total et articles[] (revenue_ht, cost, margin, margin_pct, cost_complete, group). Les valeurs sont null quand le coût n'est pas renseigné. |
staff | Heures et coût du personnel sur la période, part du chiffre d'affaires, chiffre d'affaires et commandes par heure, détail par personne (employees[]). |
curl "https://votre-domaine.arpelin.fr/api/v1/stats?start_date=2026-09-01&end_date=2026-09-30&include=summary,payments" \
-H "Authorization: Bearer arp_votre_cle_secrete"
{
"period": { "start": "2026-09-01 00:00:00", "end": "2026-09-30 23:59:59", "granularity": "day" },
"summary": {
"revenue": 18420.5, "transactions": 912, "items_sold": 2210,
"average_basket": 20.2, "average_item_price": 8.33,
"best_period": { "period": "2026-09-27", "revenue": 1104.0 },
"change_vs_previous_period_pct": { "revenue": 6.4, "transactions": 3.1, "basket": 3.2, "items": 4.9 }
},
"payments": [
{ "method": "Carte bancaire", "amount": 12980.3 },
{ "method": "Espèces", "amount": 5440.2 }
]
}
GET /api/v1/articles
Accès requis : articles. Les articles de la carte, comme dans la page Articles du backoffice,
triés dans l'ordre d'affichage, avec pagination.
| Paramètre | Défaut | Description |
|---|---|---|
id | Un seul article. | |
category_id | Articles d'une catégorie. | |
enabled | 1 pour les articles actifs, 0 pour les désactivés. | |
q | Recherche dans le nom. | |
limit | 100 | Nombre d'articles par page (1 à 500). |
offset | 0 | Décalage pour la page suivante. |
include | categories et/ou customizations pour joindre la liste complète des catégories et des personnalisations. |
articles[]| Champ | Type | Description |
|---|---|---|
id, name, description | Identifiant, nom et description. | |
category_id, category | Catégorie de l'article. | |
price | nombre | Prix TTC en euros. |
vat_rate, vat_code | Taux et code de TVA. | |
cost | nombre | null | Coût de revient, si renseigné. |
enabled | booléen | Article actif ou non. |
order | entier | Position d'affichage. |
allergens, barcode | Allergènes et code-barres. | |
hide_price | booléen | Prix masqué en boutique. |
loyalty_points_cost | entier | null | Coût en points de fidélité. |
stock, stock_tracked | Unités restantes (null si le suivi de stock est désactivé pour l'article). | |
images | tableau | URL des images. |
customization_ids | tableau | Identifiants des personnalisations proposées, dans l'ordre. Détail avec include=customizations. |
La réponse contient aussi total (nombre d'articles correspondant au filtre), limit et offset.
Une catégorie (categories[]) porte id, name, description, enabled, order,
subcategory_ids et images. Une personnalisation (customizations[]) porte id, category,
type, name, price, enabled, max_quantity, extra_price_threshold,
extra_price, cost et images.
curl "https://votre-domaine.arpelin.fr/api/v1/articles?category_id=3&enabled=1&limit=2" \
-H "Authorization: Bearer arp_votre_cle_secrete"
{
"total": 14, "limit": 2, "offset": 0,
"articles": [
{ "id": 21, "name": "Burger maison", "description": "Boeuf, cheddar, salade",
"category_id": 3, "category": "Burgers", "price": 9.5, "vat_rate": 10.0, "vat_code": null, "cost": 3.2,
"enabled": true, "order": 1, "allergens": "gluten, lait", "barcode": null, "hide_price": false,
"loyalty_points_cost": null, "stock": null, "stock_tracked": false,
"images": ["https://votre-domaine.arpelin.fr/images/articles/burger.webp"],
"customization_ids": [42, 43] }
]
}
GET /api/v1/stock
Accès requis : stock. Le stock des composants (ingrédients, emballages) tel qu'affiché dans l'onglet Stock du backoffice.
Le stock d'un composant est théorique : dernier inventaire, plus les entrées, moins les pertes, la casse, les démarques
et la consommation des ventes d'après les compositions.
| Paramètre | Défaut | Description |
|---|---|---|
include | components,articles | Sections à renvoyer, séparées par des virgules : components, alerts, movements, compositions, articles. |
status | Filtre les composants : ok, rupture (sous le seuil minimum) ou surstock. | |
component_id | Limite les composants et les mouvements à un composant. | |
movements_from, movements_to | 30 derniers jours | Période des mouvements, AAAA-MM-JJ. |
movement_type | entree, perte, casse, demarque ou inventaire. | |
movements_limit | 200 | Nombre maximum de mouvements (1 à 1000), les plus récents d'abord. |
| Section | Contenu |
|---|---|
components[] | id, name, unit, theoretical_stock, status, unit_cost, stock_value, min_threshold, max_threshold, last_inventory_at, last_inventory_gap et since_last_inventory (entries, losses, consumed_by_sales). |
alerts[] | Points d'attention : level (red ou orange), type (rupture, surstock, ecart), component, message. |
movements[] | id, component_id, component, unit, type, quantity (pour un inventaire : quantité comptée), gap, unit_cost, note, date. |
compositions[] | Quantité de composant consommée par unité vendue : target (article ou customization), target_id, component_id, quantity_per_unit_sold. |
articles[] | Stock par article : id, name, enabled, stock_tracked, stock (null si non suivi), out_of_stock. |
curl "https://votre-domaine.arpelin.fr/api/v1/stock?include=components&status=rupture" \
-H "Authorization: Bearer arp_votre_cle_secrete"
{
"generated_at": "2026-09-09 14:30:02",
"components": [
{ "id": 7, "name": "Steak haché", "unit": "kg", "theoretical_stock": 1.8, "status": "rupture",
"unit_cost": 11.5, "stock_value": 20.7, "min_threshold": 3.0, "max_threshold": 12.0,
"last_inventory_at": "2026-09-08 22:10:00", "last_inventory_gap": -0.4,
"since_last_inventory": { "entries": 5.0, "losses": 0.3, "consumed_by_sales": 6.1 } }
]
}
Le corps d'une erreur est un objet { "error": "...", "message": "..." }.
| Code HTTP | error | Cause |
|---|---|---|
400 | bad_request | Paramètre invalide (date mal formée, valeur hors limites, section inconnue). |
401 | unauthorized | Clé absente, inconnue ou révoquée. |
403 | forbidden | La clé n'a pas l'accès demandé (stats, articles ou stock). |
405 | method_not_allowed | Méthode autre que GET. |
# Mode synthétique
curl https://votre-domaine.arpelin.fr/panel/api_gestion
# Mode détaillé
curl "https://votre-domaine.arpelin.fr/panel/api_gestion?update=1"
# Mode détaillé avec adresse complète (session backoffice)
curl "https://votre-domaine.arpelin.fr/panel/api_gestion?update=1" \
--cookie "PHPSESSID=VOTRE_ID_DE_SESSION"
async function chargerCommandes() {
const res = await fetch('https://votre-domaine.arpelin.fr/panel/api_gestion', {
credentials: 'include' // envoie le cookie de session si connecté au backoffice
});
if (!res.ok) throw new Error('HTTP ' + res.status);
const commandes = await res.json();
for (const c of commandes) {
const prete = c.etat == 0.6 || c.etat == 2;
console.log(`Prép ${c.prep} — ${prete ? 'PRÊTE' : 'en cours'}`);
}
}
setInterval(chargerCommandes, 5000);
chargerCommandes();
curl "https://votre-domaine.arpelin.fr/api/v1/stats?start_date=2026-09-01&end_date=2026-09-30" \
-H "Authorization: Bearer arp_votre_cle_secrete"
curl "https://votre-domaine.arpelin.fr/api/v1/articles?include=categories,customizations" \
-H "Authorization: Bearer arp_votre_cle_secrete"
curl "https://votre-domaine.arpelin.fr/api/v1/stock?include=components,alerts,movements" \
-H "Authorization: Bearer arp_votre_cle_secrete"
import requests
BASE = "https://votre-domaine.arpelin.fr/api/v1"
HEADERS = {"Authorization": "Bearer arp_votre_cle_secrete"}
stats = requests.get(f"{BASE}/stats", headers=HEADERS,
params={"start_date": "2026-09-01", "end_date": "2026-09-30",
"include": "summary,top_articles"}, timeout=30)
stats.raise_for_status()
print(stats.json()["summary"]["revenue"])
notefunction nomClient(note) {
if (!note) return null;
const m = note.match(/\[(?:Nom|Name)[^:]*:\s*([^\]]+)\]/i);
return m ? m[1].trim() : null;
}