Votre cuisine, en HTTPS.
Tout ce que Chefrys One sait d'une cuisine — recettes, coûts, stock, inventaires, commandes, ventes, écarts — est accessible en lecture avec une clé API, et les moments importants arrivent sous forme de webhooks signés. Aucun SDK à installer; tout langage capable de faire une requête HTTPS fera l'affaire.
Authentification
Un gérant ou un propriétaire crée une clé sous Intégrations → API & webhooks dans la barre latérale. La clé n'est affichée qu'une seule fois. Envoyez-la comme jeton porteur (bearer token) :
curl https://www.chefrys.com/recipes \
-H "Authorization: Bearer cos_0123456789abcdef…"
Une clé agit pour une seule cuisine avec un accès de chef : toutes les lectures et écritures opérationnelles, mais jamais le personnel, la facturation, les exports ou le journal d'audit. Révoquez-la en tout temps depuis le même écran; chaque requête qu'elle a faite figure dans le journal d'activité de la cuisine sous le nom de la clé.
Points d'accès les plus utilisés par les intégrations
| Méthode · chemin | Ce qu'il retourne ou fait |
|---|---|
GET /recipes | Toutes les recettes avec le coût, le prix, le % de coût des aliments et l'état de complétude. |
GET /recipes/{id}/rollup | Une recette complète : ingrédients en grammes, sous-recettes, étapes, allergènes, coût du lot et de la portion. |
GET /ingredients | La bibliothèque d'ingrédients avec les prix par gramme, les rendements et les catégories. |
GET /suppliers | Articles fournisseur : paquet, poids du paquet (pack_g, grammes), prix du paquet, code. pack_g 0 est un article vendu à l'unité (gants, plats en aluminium, une location) : il a un prix de paquet, mais aucun prix par gramme, donc il faut l'exclure de tout calcul par gramme. |
GET /inventory/full | Stock en main avec les valeurs et les niveaux par. |
GET /count/sheet?date=YYYY-MM-DD · POST /count | La feuille d'inventaire en unités de tablette, et l'enregistrement des inventaires ({date, lines:[{id, entries:[{key, qty}]}]}). |
GET /variance?from=&to= | Écart de période entre deux inventaires : ouverture + achats − fermeture vs idéal, en grammes et en dollars. headline.actual_pct et headline.ideal_pct (le coût des aliments en % de toutes les ventes d'aliments de la période, incluant les lignes de la caisse sans recette) sont null sauf si headline.stated est vrai : les articles comptés aux deux extrémités représentent au moins coverage_min% de l'utilisation des recettes de la période en dollars (coverage_pct; items_used / items_used_counted), aucun d'eux n'a été utilisé sans prix (unpriced_used), et les ventes sans recette représentent au plus no_recipe_max% des ventes (sales_no_recipe_pct). headline.complete est vrai seulement lorsque, de plus, aucun article utilisé par les recettes n'est sans prix (unpriced_uncounted, unpriced_uncounted_names: aucune couverture en dollars ne peut les voir). actual_cogs / ideal_cogs couvrent toujours uniquement les articles comptés, et counted_vs_recipe_pct les compare. sales_revenue correspond à toutes les ventes d'aliments de la période; sales_unmatched la partie vendue sans recette. |
GET /menu-engineering?range=30&by=category | Étoiles, chevaux de labour, énigmes et chiens, avec marge et popularité. |
GET /sales · GET /sales/pending | Historique des ventes, et noms POS pas encore liés à une recette. |
GET /order · GET /orders · POST /orders/place | La feuille de commande suggérée, les commandes passées, et la mise en place d'une commande. |
GET /invoices | Factures enregistrées avec leurs lignes. |
GET /price-watch | Variations de prix des fournisseurs des 30 derniers jours et les plats touchés. |
GET /prep · GET /plan | La liste de préparation du jour et le plan de production. |
POST /message | Envoyez un document (multipart files[]) ou texte à lire — le même chemin que le compositeur; consomme les jetons de la cuisine. Avec des fichiers, la réponse revient d'un coup avec un batch_id; interrogez GET /message/batch/{id} pour les résultats au fur et à mesure qu'ils arrivent (chacun livré une seule fois) jusqu'à terminé. |
Les réponses sont en JSON. Les dates sont au format YYYY-MM-DD; les poids sont en grammes; l'argent est dans la devise propre à la cuisine, comme sur ses factures (dollars canadiens pour une cuisine canadienne). Les erreurs comportent {"detail": "…"} avec les codes de statut habituels; une clé qui ne peut pas faire quelque chose reçoit 403. Tant qu'il n'y a rien à afficher (aucun plan ou aucun inventaire), ces trois éléments retournent un statut 404: GET /prep, /order et /variance. Ajouter empty=1 à la requête pour obtenir 200 {"empty": true, "detail": "…"} à la place.
Webhooks
Enregistrez une URL HTTPS sous le même écran et choisissez les événements. Chaque livraison est un POST JSON :
{
"event": "count.finalized",
"kitchen": "the_bistro",
"ts": 1789300000.123,
"data": {"date": "2026-09-13", "items": 212, "value": 18342.10, "by": "marco"}
}
| Événement | Quand | Données |
|---|---|---|
count.finalized | Un inventaire est verrouillé pour une date. | date, items, value, by |
stock.low | Des articles sont passés sous le niveau par (après un inventaire, une livraison ou les ventes du jour); les commandes suggérées qui ont été rédigées. | trigger, items[{id, ingredient, on_hand_g, par_g, short_g, supplier, new}], suggested_orders[{id, supplier, lines, total}] |
order.called | Chefrys One a appelé un fournisseur et a lu une commande à voix haute. | id, supplier, to, lines, by, sid |
order.confirmed | Le fournisseur a confirmé une commande : a cliqué sur Confirmer dans le courriel, a répondu par courriel, ou a appuyé sur 1 lors de l'appel. | id, supplier, via (link | reply | call), note |
order.problem | Une commande nécessite l'intervention d'une personne : le courriel a rebondi, le fournisseur a dit qu'il ne pouvait pas la remplir, ou sa réponse semble poser problème. | id, supplier, problem (bounced | declined | reply), detail |
order.call_ended | Comment cet appel s'est déroulé (terminé, occupé, sans réponse…) et ce que le fournisseur a appuyé. | id, supplier, status, seconds, answered_by, result (confirmed | declined) |
order.placed | Les lignes de la feuille de commande deviennent des bons de commande. | orders: [{id, supplier, lines, total}] |
order.sent | Un bon de commande est envoyé par courriel au fournisseur. | id, supplier, to, lines |
price.alert | Le prix d'un fournisseur a suffisamment changé pour modifier les coûts des assiettes. | ingredient, pct, old_pack_price, new_pack_price, dishes |
invoice.received | Une facture a été lue et ses achats ont été enregistrés. | fournisseur, numéro, date, total, lignes (lignes alimentaires), fournitures, coût_fournitures (lignes non alimentaires, exclues du coût des aliments) |
sales.synced | Les ventes sont arrivées d'un POS connecté. | source, days, rows, matched, unmatched |
webhook.test | Vous avez appuyé sur Tester. | hello |
Vérifiez chaque livraison. L'en-tête X-ChefOS-Signature est sha256= suivi du HMAC-SHA256 hexadécimal du corps brut de la requête, avec pour clé le secret du webhook (affiché une seule fois lors de sa création). Rejetez tout ce qui ne correspond pas. Répondez avec un 2xx en moins de huit secondes; Chefrys One réessaie une fois, puis met en pause un webhook après vingt échecs consécutifs.
# Python
import hmac, hashlib
expected = "sha256=" + hmac.new(SECRET.encode(), request_body_bytes, hashlib.sha256).hexdigest()
ok = hmac.compare_digest(expected, request.headers["X-ChefOS-Signature"])
Limites et utilisation équitable
Les clés consomment les jetons de la cuisine et partagent son plafond quotidien lorsqu'elles envoient des documents ou des questions. Les lectures simples sont gratuites. Soyez indulgent : quelques requêtes par seconde, ça va; un robot d'exploration, non. Questions : chefrys.com/talk.