Aller au contenu principal

Intégration de l'interface de programmation personnalisée

Ce guide fournit les détails techniques pour intégrer Eaternity Forecast à votre système de caisse, progiciel de gestion intégré ou système de gestion de cuisine personnalisé via notre interface de programmation REST.

Aperçu de l'interface de programmation

URL de base

Production : https://api.eaternity.org/v1/forecast
Bac a sable : https://sandbox-api.eaternity.org/v1/forecast

Recommandation : Developpez et testez dans l'environnement bac à sable avant le déploiement en production.

Authentification

Méthodes supportees :

  1. OAuth 2.0 (recommandé pour les applications orientees utilisateur)
  2. Clés d'interface de programmation (recommandé pour l'intégration serveur à serveur)

Exigences de sécurité :

  • Toutes les requêtes doivent utiliser HTTPS
  • TLS 1.2 ou supérieur requis
  • Les clés d'interface de programmation doivent être stockées de manière sécurisée (variables d'environnement, gestionnaires de secrets)

Voir la documentation de l'interface de programmation Eaternity →

Limites de débit

Limites standard :

  • 100 requêtes par minute
  • 10 000 requêtes par jour
  • Allocation de rafale : 150 requêtes en 60 secondes

Limites personnalisées :

  • Disponibles pour les intégrations à fort volume
  • Contactez le support pour les demandes d'augmentation de limité

En-têtes de limité de débit :

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 87
X-RateLimit-Reset: 1705752000

Démarrage rapide

1. Obtenir les identifiants de l'interface de programmation

Étape 1 : Contactez Eaternity pour l'accès à l'interface de programmation

Étape 2 : Recevez les identifiants de l'interface de programmation

  • Clé d'interface de programmation pour l'authentification
  • ID cuisine pour votre établissement
  • Accès à l'environnement bac à sable

Étape 3 : Testez l'authentification

curl -X GET "https://sandbox-api.eaternity.org/v1/forecast/ping" \
-H "Authorization: Bearer votre_cle_api_ici"

# Reponse de succes :
{
"status": "success",
"message": "Authentication successful",
"kitchen_id": "votre_id_cuisine"
}

2. Soumettre les données historiques

Point d'accès : POST /v1/forecast/sales/bulk

Exemple de requête :

curl -X POST "https://api.eaternity.org/v1/forecast/sales/bulk" \
-H "Authorization: Bearer votre_cle_api" \
-H "Content-Type: application/json" \
-d '{
"kitchen_id": "votre_id_cuisine",
"start_date": "2023-10-01",
"end_date": "2024-01-15",
"sales": [
{
"date": "2023-10-01",
"service_period": "lunch",
"items": [
{
"item_id": "pasta_carbonara",
"name": "Pasta Carbonara",
"quantity_sold": 52,
"price": 14.50,
"category": "Main Course"
},
{
"item_id": "caesar_salad",
"name": "Caesar Salad",
"quantity_sold": 31,
"price": 9.00,
"category": "Starter"
}
]
}
]
}'

Réponse :

{
"status": "success",
"message": "Historical data import queued",
"import_id": "imp_1234567890",
"total_records": 92,
"estimated_processing_time": "15 minutes",
"status_url": "/v1/forecast/imports/imp_1234567890/status"
}

3. Vérifier le statut de l'import

Point d'accès : GET /v1/forecast/imports/{import_id}/status

curl -X GET "https://api.eaternity.org/v1/forecast/imports/imp_1234567890/status" \
-H "Authorization: Bearer votre_cle_api"

Réponse :

{
"import_id": "imp_1234567890",
"status": "processing",
"progress": 65,
"records_processed": 60,
"records_total": 92,
"records_failed": 0,
"errors": [],
"estimated_completion": "2024-01-20T10:35:00Z"
}

Valeurs de statut :

  • queued — En attente de traitement
  • processing — Import en cours
  • validating — Vérification de la qualité des données
  • completed — Import reussi
  • failed — L'import à rencontre des erreurs

4. Recuperer les prévisions

Point d'accès : GET /v1/forecast/predictions

curl -X GET "https://api.eaternity.org/v1/forecast/predictions?date=2024-01-20" \
-H "Authorization: Bearer votre_cle_api"

Réponse :

{
"kitchen_id": "votre_id_cuisine",
"generated_at": "2024-01-20T03:15:42Z",
"predictions": [
{
"date": "2024-01-20",
"day_of_week": "Saturday",
"items": [
{
"item_id": "pasta_carbonara",
"name": "Pasta Carbonara",
"predicted_quantity": 52,
"confidence_interval": {
"lower": 48,
"upper": 56
},
"confidence_score": 0.92,
"accuracy_last_30_days": 94.2,
"factors": {
"day_of_week_effect": 1.05,
"weather_effect": 1.02,
"trend": "stable"
}
}
]
}
]
}

Points d'accès de l'interface de programmation

Points d'accès des données de ventes

Soumettre les ventes quotidiennes

POST /v1/forecast/sales

Soumettre les données de ventes pour une seule journée.

Corps de la requête :

{
"kitchen_id": "votre_id_cuisine",
"date": "2024-01-19",
"service_periods": [
{
"period": "lunch",
"items": [
{
"item_id": "pasta_carbonara",
"name": "Pasta Carbonara",
"quantity_sold": 52,
"price": 14.50,
"category": "Main Course"
}
]
},
{
"period": "dinner",
"items": [
{
"item_id": "grilled_salmon",
"name": "Grilled Salmon",
"quantity_sold": 38,
"price": 18.50,
"category": "Main Course"
}
]
}
]
}

Réponse :

{
"status": "success",
"date": "2024-01-19",
"items_processed": 12,
"next_prediction_update": "2024-01-20T03:00:00Z"
}

Codes de statut :

  • 200 — Succes
  • 400 — Données de requête invalides
  • 401 — Échec de l'authentification
  • 422 — Échec de la validation des données
  • 429 — Limité de débit depassee

Import historique en masse

POST /v1/forecast/sales/bulk

Importer de gros volumes de données historiques.

Corps de la requête :

{
"kitchen_id": "votre_id_cuisine",
"start_date": "2023-10-01",
"end_date": "2024-01-15",
"sales": [
{
"date": "2023-10-01",
"service_period": "lunch",
"items": [...]
}
]
}

Réponse :

{
"status": "success",
"import_id": "imp_1234567890",
"total_records": 92,
"status_url": "/v1/forecast/imports/imp_1234567890/status"
}

Meilleures pratiques :

  • Maximum 365 jours par import en masse
  • Maximum 10 000 enregistrements par requête
  • Pour les ensembles de données plus volumineux, divisez en plusieurs requêtes
  • Surveillez le statut de l'import via le point d'accès de statut

Mettre à jour les données de ventes

PATCH /v1/forecast/sales/{date}

Corriger les données de ventes precedemment soumises.

Corps de la requête :

{
"kitchen_id": "votre_id_cuisine",
"items": [
{
"item_id": "pasta_carbonara",
"quantity_sold": 54
}
]
}

Cas d'utilisation :

  • Corriger les erreurs de saisie
  • Mettre à jour avec les comptages finaux de fin de journée
  • Ajouter des périodes de service manquantes

Points d'accès des prévisions

Obtenir les prévisions pour une plage de dates

GET /v1/forecast/predictions

Paramètres de requête :

  • date (obligatoire) — Date ou date de début (AAAA-MM-JJ)
  • end_date (optionnel) — Date de fin pour la plage (AAAA-MM-JJ)
  • items (optionnel) — IDs d'articles séparés par des virgules pour filtrer

Exemples :

# Date unique
GET /v1/forecast/predictions?date=2024-01-20

# Plage de dates (7 prochains jours)
GET /v1/forecast/predictions?date=2024-01-20&end_date=2024-01-27

# Articles specifiques uniquement
GET /v1/forecast/predictions?date=2024-01-20&items=pasta_carbonara,grilled_salmon

Réponse :

{
"kitchen_id": "votre_id_cuisine",
"generated_at": "2024-01-20T03:15:42Z",
"predictions": [
{
"date": "2024-01-20",
"day_of_week": "Saturday",
"items": [...]
},
{
"date": "2024-01-21",
"day_of_week": "Sunday",
"items": [...]
}
]
}

Obtenir la prévision pour un article unique

GET /v1/forecast/predictions/{item_id}

Paramètres de requête :

  • date (obligatoire) — Date de prévision
  • days_ahead (optionnel) — Nombre de jours à prevoir (par défaut : 7, max : 14)

Exemple :

GET /v1/forecast/predictions/pasta_carbonara?date=2024-01-20&days_ahead=7

Réponse :

{
"item_id": "pasta_carbonara",
"name": "Pasta Carbonara",
"predictions": [
{
"date": "2024-01-20",
"predicted_quantity": 52,
"confidence_interval": {
"lower": 48,
"upper": 56
},
"confidence_score": 0.92
}
],
"historical_accuracy": {
"last_7_days": 95.2,
"last_30_days": 94.2,
"all_time": 93.8
}
}

Modifier une prévision

POST /v1/forecast/predictions/override

Modifier manuellement une prévision pour des circonstances spécifiques.

Corps de la requête :

{
"kitchen_id": "votre_id_cuisine",
"date": "2024-01-25",
"item_id": "pasta_carbonara",
"override_quantity": 75,
"reason": "Conference group booking (50 pax confirmed)",
"preserve_ratios": true
}

Paramètres :

  • override_quantity (obligatoire) — Nouvelle quantité prévue
  • reason (obligatoire) — Explication de la modification (utilisée pour l'apprentissage)
  • preserve_ratios (optionnel) — Ajuster les articles associés proportionnellement

Réponse :

{
"status": "success",
"original_prediction": 52,
"override_quantity": 75,
"affected_items": [
{
"item_id": "caesar_salad",
"original": 31,
"adjusted": 45
}
]
}

Points d'accès analytiques

Obtenir le rapport de précision

GET /v1/forecast/analytics/accuracy

Paramètres de requête :

  • start_date (obligatoire) — Date de début du rapport
  • end_date (obligatoire) — Date de fin du rapport
  • group_by (optionnel) — day, week, month, ou item

Exemple :

GET /v1/forecast/analytics/accuracy?start_date=2024-01-01&end_date=2024-01-31&group_by=week

Réponse :

{
"period": {
"start": "2024-01-01",
"end": "2024-01-31"
},
"overall_mape": 12.3,
"by_week": [
{
"week": 1,
"start_date": "2024-01-01",
"mape": 13.5,
"items_within_10_percent": 52,
"total_items": 65
}
],
"top_performers": [
{
"item_id": "pasta_carbonara",
"mape": 8.2
}
],
"needs_attention": [
{
"item_id": "daily_special",
"mape": 22.1,
"reason": "High variance, new items frequently"
}
]
}

Obtenir le rapport de réduction du gaspillage

GET /v1/forecast/analytics/waste-reduction

Suivre les économies de gaspillage alimentaire depuis l'utilisation de Forecast.

Paramètres de requête :

  • baseline_start (obligatoire) — Début de la période de référence (avant Forecast)
  • baseline_end (obligatoire) — Fin de la période de référence
  • comparison_start (obligatoire) — Début de la période d'utilisation de Forecast
  • comparison_end (obligatoire) — Fin de la période d'utilisation de Forecast

Réponse :

{
"baseline": {
"period": "2023-10-01 to 2023-12-31",
"waste_rate": 12.8,
"total_waste_portions": 3845,
"estimated_cost": 21148.50
},
"comparison": {
"period": "2024-01-01 to 2024-03-31",
"waste_rate": 7.2,
"total_waste_portions": 2156,
"estimated_cost": 11858.00
},
"improvement": {
"waste_rate_reduction": 43.8,
"portions_saved": 1689,
"cost_savings": 9290.50,
"annualized_savings": 11748.60
}
}

Webhooks

Aperçu

Les webhooks permettent à Forecast d'envoyer des notifications à votre système au lieu de nécessiter un polling.

Cas d'utilisation :

  • Recevoir des notifications quand de nouvelles prévisions sont pretes
  • Obtenir des alertes pour les grandes variances entre prévision et réel
  • Surveiller les problèmes de qualité des données
  • Suivre les événements de re-entrainement du modèle

Configuration

Configurer le point d'accès webhook :

POST /v1/forecast/webhooks

{
"kitchen_id": "votre_id_cuisine",
"url": "https://votre-systeme.com/webhooks/forecast",
"events": [
"predictions.generated",
"variance.large",
"data.quality_issue",
"model.retrained"
],
"secret": "votre_secret_webhook_pour_validation_signature"
}

Réponse :

{
"webhook_id": "wh_1234567890",
"status": "active",
"events": ["predictions.generated", "variance.large"],
"created_at": "2024-01-20T10:00:00Z"
}

Événements webhook

predictions.generated

Déclenche quand de nouvelles prévisions sont générées (quotidiennement à 3h00).

Payload :

{
"event": "predictions.generated",
"timestamp": "2024-01-20T03:15:42Z",
"kitchen_id": "votre_id_cuisine",
"data": {
"date_range": {
"start": "2024-01-20",
"end": "2024-01-27"
},
"total_items": 65,
"prediction_url": "/v1/forecast/predictions?date=2024-01-20"
}
}

variance.large

Déclenche quand les ventes réelles different significativement de la prévision (plus de 20 % par défaut).

Payload :

{
"event": "variance.large",
"timestamp": "2024-01-19T21:30:00Z",
"kitchen_id": "votre_id_cuisine",
"data": {
"date": "2024-01-19",
"item_id": "grilled_salmon",
"predicted": 28,
"actual": 42,
"variance_percent": 50.0,
"possible_causes": ["weather_warmer_than_forecast", "event_nearby"]
}
}

data.quality_issue

Déclenche quand des problèmes de qualité des données sont détectés.

Payload :

{
"event": "data.quality_issue",
"timestamp": "2024-01-20T04:00:00Z",
"kitchen_id": "votre_id_cuisine",
"data": {
"issue_type": "missing_data",
"severity": "warning",
"description": "No sales data received for 2024-01-19",
"recommendation": "Submit sales data for 2024-01-19 to maintain prediction accuracy"
}
}

model.retrained

Déclenche quand le modèle est re-entraîne avec de nouvelles données (hebdomadairement).

Payload :

{
"event": "model.retrained",
"timestamp": "2024-01-20T04:30:00Z",
"kitchen_id": "votre_id_cuisine",
"data": {
"training_data_range": {
"start": "2023-10-01",
"end": "2024-01-19"
},
"accuracy_improvement": 1.2,
"new_mape": 12.1,
"previous_mape": 13.3
}
}

Sécurité des webhooks

Validation de signature :

Toutes les requêtes webhook incluent l'en-tête X-Forecast-Signature pour vérification.

Exemple de vérification (Python) :

import hmac
import hashlib

def verify_webhook_signature(payload, signature, secret):
expected_signature = hmac.new(
secret.encode('utf-8'),
payload.encode('utf-8'),
hashlib.sha256
).hexdigest()

return hmac.compare_digest(signature, expected_signature)

# Dans votre gestionnaire de webhook :
payload = request.body
signature = request.headers['X-Forecast-Signature']
secret = 'votre_secret_webhook'

if verify_webhook_signature(payload, signature, secret):
# Traiter le webhook
pass
else:
# Rejeter la requete (probleme de securite potentiel)
return 401

Formats de données et validation

Exigences d'ID d'article

Format :

  • Caractères alphanumériques, underscores, tirets uniquement
  • Maximum 100 caractères
  • Sensible à la casse
  • Doit être coherent sur toutes les requêtes

Bons exemples :

  • pasta_carbonara
  • grilled-salmon-lemon
  • ITEM_12345

Mauvais exemples :

  • Pasta Carbonara (contient des espaces)
  • item#12345 (contient un caractere spécial)
  • Casse differente : Pasta_Carbonara vs pasta_carbonara (incoherent)

Format de date

Format requis : AAAA-MM-JJ (ISO 8601)

Valide :

  • 2024-01-20
  • 2024-12-31

Invalide :

  • 20-01-2024 (mauvais ordre)
  • 2024/01/20 (barres obliques au lieu de tirets)
  • 2024-1-20 (pas de zéro initial)

Validation des quantités

Exigences :

  • Valeurs entieres uniquement
  • Minimum : 0
  • Maximum : 10 000 (contactez le support pour des limites supérieures)
  • Valeurs négatives rejetees

Validation des prix

Exigences :

  • Valeurs decimales (2 decimales)
  • Minimum : 0,00
  • Maximum : 999,99
  • Devise non spécifiée (utilisez une devise cohérente sur toutes les données)

Gestion des erreurs

Format de réponse d'erreur

{
"status": "error",
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid date format",
"details": {
"field": "date",
"value": "20-01-2024",
"expected": "YYYY-MM-DD"
}
}
}

Codes d'erreur courants

CodeStatut HTTPDescriptionSolution
AUTHENTICATION_FAILED401Clé d'interface de programmation invalideVérifiez que la clé est correcte
RATE_LIMIT_EXCEEDED429Trop de requêtesAttendez et reessayez, ou demandez une augmentation de limité
VALIDATION_ERROR422Format de données invalideVérifiez le format de la requête contre la documentation
NOT_FOUND404Ressource non trouvéeVérifiez kitchen_id ou item_id
INTERNAL_ERROR500Erreur serveurReessayez avec backoff exponentiel

Logique de reessai

Stratégie de reessai recommandée :

import time
import requests

def make_request_with_retry(url, max_retries=3):
for attempt in range(max_retries):
try:
response = requests.get(url)

if response.status_code == 200:
return response.json()
elif response.status_code == 429:
# Limite de debit - attendre et reessayer
retry_after = int(response.headers.get('Retry-After', 60))
time.sleep(retry_after)
elif response.status_code >= 500:
# Erreur serveur - backoff exponentiel
wait_time = 2 ** attempt
time.sleep(wait_time)
else:
# Erreur client - ne pas reessayer
raise Exception(f"Error {response.status_code}: {response.text}")

except requests.exceptions.RequestException as e:
if attempt == max_retries - 1:
raise
time.sleep(2 ** attempt)

raise Exception("Max retries exceeded")

SDK et bibliothèques client

SDK officiels

SDK Python (Recommandé) :

pip install eaternity-forecast

Utilisation :

from eaternity_forecast import ForecastClient

client = ForecastClient(api_key='votre_cle_api')

# Soumettre les ventes quotidiennes
client.sales.submit(
date='2024-01-19',
items=[
{'item_id': 'pasta_carbonara', 'quantity_sold': 52}
]
)

# Obtenir les previsions
predictions = client.predictions.get(date='2024-01-20')

SDK JavaScript/TypeScript :

npm install @eaternity/forecast-sdk

Utilisation :

import { ForecastClient } from '@eaternity/forecast-sdk';

const client = new ForecastClient({ apiKey: 'votre_cle_api' });

// Obtenir les previsions
const predictions = await client.predictions.get({ date: '2024-01-20' });

SDK communautaires :

  • Ruby : gem install eaternity-forecast
  • PHP : composer require eaternity/forecast-sdk
  • Go : go get github.com/eaternity/forecast-go

Voir la documentation SDK →

Tests

Environnement bac à sable

Objectif : Tester l'intégration sans affecter les données de production

URL de base : https://sandbox-api.eaternity.org/v1/forecast

Fonctionnalités :

  • Identifiants d'authentification séparés
  • Les données de test peuvent être réinitialisées
  • Même interface de programmation qu'en production
  • Génération de prévisions plus rapide (pour les tests)

Limitations :

  • Les prévisions peuvent être moins précises (utilisant des données synthétiques)
  • Pas de garantie de niveau de service
  • Données réinitialisées hebdomadairement

Exemple de test d'intégration

import unittest
from eaternity_forecast import ForecastClient

class TestForecastIntegration(unittest.TestCase):
def setUp(self):
self.client = ForecastClient(
api_key='sandbox_api_key',
base_url='https://sandbox-api.eaternity.org/v1/forecast'
)

def test_submit_sales_and_get_predictions(self):
# Soumettre les donnees historiques
response = self.client.sales.submit(
date='2024-01-19',
items=[
{'item_id': 'test_item_1', 'quantity_sold': 50},
{'item_id': 'test_item_2', 'quantity_sold': 30}
]
)
self.assertEqual(response['status'], 'success')

# Attendre le traitement (le bac a sable est plus rapide)
time.sleep(10)

# Obtenir les previsions
predictions = self.client.predictions.get(date='2024-01-20')
self.assertIsNotNone(predictions)
self.assertGreater(len(predictions['predictions']), 0)

Liste de vérification du déploiement en production

Avant le lancement

  • Teste tous les points d'accès dans l'environnement bac a sable
  • Implémente la gestion des erreurs et la logique de reessai
  • Configure les points d'accès webhook (si utilisés)
  • Vérifie la validation de signature webhook
  • Mis en place la surveillance et la journalisation
  • Documenté l'intégration pour l'équipe
  • Obtenu les identifiants d'interface de programmation de production
  • Importe les données historiques avec succes
  • Vérifie la note de qualité des données supérieure a 80 %
  • Complete l'entrainement du modèle

Mise en production

  • Bascule des URLs bac a sable vers production
  • Mis a jour les identifiants d'interface de programmation vers production
  • Surveille les premières 24 heures de prévisions
  • Vérifie la soumission quotidienne des ventes fonctionnelle
  • Confirmé la récupération des prévisions fonctionnelle
  • Vérifie la livraison des webhooks (si configure)

Après le lancement

  • Suit les métriques de précision hebdomadairement
  • Examine et répond aux alertes de grandes variances
  • Fournit des retours sur la qualité des prévisions
  • Optimise les flux de préparation bases sur la confiance
  • Planifié des revues de performance mensuelles

Support

Support technique

E-mail : forecast-api@eaternity.org

Delais de réponse :

  • Critique (production hors service) : 4 heures
  • Eleve (performance degradee) : 24 heures
  • Moyen (questions, bogues) : 48 heures
  • Faible (améliorations) : 1 semaine

Inclure dans les demandes de support :

  • ID cuisine
  • Point d'accès et méthode de l'interface de programmation
  • Exemples de requête/réponse
  • Messages d'erreur
  • Horodatage du problème

Documentation

Voir aussi