Développeurs

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 · cheminCe qu'il retourne ou fait
GET /recipesToutes les recettes avec le coût, le prix, le % de coût des aliments et l'état de complétude.
GET /recipes/{id}/rollupUne recette complète : ingrédients en grammes, sous-recettes, étapes, allergènes, coût du lot et de la portion.
GET /ingredientsLa bibliothèque d'ingrédients avec les prix par gramme, les rendements et les catégories.
GET /suppliersArticles 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/fullStock en main avec les valeurs et les niveaux par.
GET /count/sheet?date=YYYY-MM-DD · POST /countLa 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/pendingHistorique des ventes, et noms POS pas encore liés à une recette.
GET /order · GET /orders · POST /orders/placeLa feuille de commande suggérée, les commandes passées, et la mise en place d'une commande.
GET /invoicesFactures enregistrées avec leurs lignes.
GET /price-watchVariations de prix des fournisseurs des 30 derniers jours et les plats touchés.
GET /prep · GET /planLa liste de préparation du jour et le plan de production.
POST /messageEnvoyez 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énementQuandDonnées
count.finalizedUn inventaire est verrouillé pour une date.date, items, value, by
stock.lowDes 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.calledChefrys One a appelé un fournisseur et a lu une commande à voix haute.id, supplier, to, lines, by, sid
order.confirmedLe 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.problemUne 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_endedComment 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.placedLes lignes de la feuille de commande deviennent des bons de commande.orders: [{id, supplier, lines, total}]
order.sentUn bon de commande est envoyé par courriel au fournisseur.id, supplier, to, lines
price.alertLe prix d'un fournisseur a suffisamment changé pour modifier les coûts des assiettes.ingredient, pct, old_pack_price, new_pack_price, dishes
invoice.receivedUne 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.syncedLes ventes sont arrivées d'un POS connecté.source, days, rows, matched, unmatched
webhook.testVous 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.