Documentation API
Affreta expose une API REST, un serveur MCP pour les assistants IA et des webhooks signés pour intégrer vos appels d'offres transport à votre ERP, WMS ou vos scripts. Cette documentation est publique. Pour appeler l'API, générez une clé dans l'application → Intégrations API.
Base & authentification
URL de base : https://app.affreta.com
Chaque requête s'authentifie par une clé d'organisation, dans l'en-tête Authorization :
Authorization: Bearer aff_live_xxxxxxxxxxxxxxxxxxxxxxxx
La clé se génère dans l'app (Intégrations API), est affichée une seule fois, stockée hachée, et révocable à tout moment. Une clé peut porter le scope write (nécessaire pour créer). Sans clé valide, l'API répond 401.
Endpoints
GET /api/v1/requests
Liste les demandes de l'organisation, les plus récentes d'abord. Paramètres : limit (défaut 50, max 200), statut (filtre optionnel).
curl -H "Authorization: Bearer aff_live_xxx" \ "https://app.affreta.com/api/v1/requests?statut=cloture&limit=50"
Réponse : { "data": [ … ] }. Chaque demande contient notamment : id, reference, statut, type_transport, date_enlevement, date_livraison, adresse_enlevement, adresse_livraison, partenaire, nature_marchandise, nb_colis, poids_kg, volume_m3, offers_count, replies_count, best_offer ({ transporteur, price_eur, delai_jours }) et le détail offers[].
POST /api/v1/requests
Crée une demande (en brouillon) depuis un système tiers. Nécessite le scope write.
| Champ | Type | Requis |
|---|---|---|
date_enlevement | string (YYYY-MM-DD) | oui |
type_transport | depart | reception | non |
date_livraison | string (YYYY-MM-DD) | non |
reference, partenaire | string | non |
adresse_enlevement, adresse_livraison | string | non |
nb_colis, poids_kg, volume_m3 | number | non |
nature_marchandise, notes | string | non |
curl -X POST "https://app.affreta.com/api/v1/requests" \ -H "Authorization: Bearer aff_live_xxx" \ -H "Content-Type: application/json" \ -d '{ "date_enlevement": "2026-10-02", "adresse_enlevement": "Lyon 69007", "adresse_livraison": "Nantes 44000", "nb_colis": 12, "poids_kg": 4200, "reference": "CMD-10482" }'
Réponse : { "id": "…", "statut": "brouillon" } (HTTP 201).
GET /api/v1/requests/:id
Détail d'une demande et de ses offres (mêmes champs que la liste, dont offers[] avec l'id de chaque offre — utile pour l'attribution).
curl -H "Authorization: Bearer aff_live_xxx" \ "https://app.affreta.com/api/v1/requests/REQUEST_ID"
POST /api/v1/requests/:id/send
Diffuse un brouillon à ses transporteurs (envoie les emails de consultation, calcule le trajet, passe la demande en envoye). Nécessite le scope write. Ajoutez d'abord les transporteurs à la demande.
curl -X POST "https://app.affreta.com/api/v1/requests/REQUEST_ID/send" \ -H "Authorization: Bearer aff_live_xxx"
Réponse : { "id": "…", "statut": "envoye", "emailed": { "sent": n, "skipped": n, "failed": n } }.
POST /api/v1/requests/:id/award
Attribue la demande à une offre : offre retenue confirmée, écartés notifiés, ligne de coût créée, email de confirmation envoyé. Nécessite le scope write. Fournissez soit une offre précise, soit une stratégie automatique.
| Champ | Type | Description |
|---|---|---|
offer_id | string | Offre à retenir (voir offers[].id) |
strategy | cheapest · fastest | Retient automatiquement l'offre chiffrée la moins chère, ou celle au délai le plus court |
curl -X POST "https://app.affreta.com/api/v1/requests/REQUEST_ID/award" \ -H "Authorization: Bearer aff_live_xxx" \ -H "Content-Type: application/json" \ -d '{ "strategy": "cheapest" }'
Réponse : { "id": "…", "statut": "confirme", "offer_id": "…" }.
GET /api/v1/offers
Liste les offres de l'organisation (toutes demandes). Filtres : statut (en_attente | accepte | refuse), request_id, limit (défaut 100, max 500).
curl -H "Authorization: Bearer aff_live_xxx" \ "https://app.affreta.com/api/v1/offers?statut=accepte"
GET /api/v1/carriers
Liste les transporteurs (panel) de l'organisation.
curl -H "Authorization: Bearer aff_live_xxx" \ "https://app.affreta.com/api/v1/carriers"
Serveur MCP (assistants IA)
Affreta parle le Model Context Protocol : branchez votre compte dans Claude Code, Claude Desktop, Cursor ou VS Code (Copilot) et pilotez vos appels d'offres en langage naturel : « crée une demande Lyon → Marseille, 12 palettes, enlèvement mardi, et envoie-la à mon panel », « qui est le moins cher sur l'AO-2418 ? attribue-la ».
URL : https://app.affreta.com/api/mcp (transport HTTP « Streamable »). Authentification par la même clé API que l'API REST : l'assistant ne voit que votre organisation, et une clé read l'empêche d'envoyer ou d'attribuer.
Claude Code
claude mcp add --transport http affreta https://app.affreta.com/api/mcp \
--header "Authorization: Bearer aff_live_xxx"
Cursor (.cursor/mcp.json) · VS Code (.vscode/mcp.json, clé servers)
{
"mcpServers": {
"affreta": {
"url": "https://app.affreta.com/api/mcp",
"headers": { "Authorization": "Bearer aff_live_xxx" }
}
}
}
Claude Desktop (claude_desktop_config.json)
{
"mcpServers": {
"affreta": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://app.affreta.com/api/mcp",
"--header", "Authorization: Bearer ${AFFRETA_KEY}"],
"env": { "AFFRETA_KEY": "aff_live_xxx" }
}
}
}
Outils exposés
| Outil | Rôle |
|---|---|
get_organization | votre organisation et la date du jour (pour « mardi prochain ») |
list_carriers | transporteurs du panel |
list_requests · get_request | demandes et leurs offres (par id ou référence) |
list_offers | offres reçues |
create_request | crée un brouillon (rien n'est envoyé) |
send_request | envoie la demande aux transporteurs — après votre accord |
award_request | attribue (offre précise, la moins chère ou la plus rapide) — après votre accord |
Les actions qui envoient des emails à des transporteurs sont signalées comme telles à l'assistant, qui vous demande confirmation avant de les exécuter. Limite : 120 appels par minute et par clé.
Scopes des clés
Chaque clé porte un scope choisi à sa création : read (lecture seule) ou read + write (lecture et écriture). Les endpoints POST exigent le scope write, sinon l'API répond 403.
Webhooks
Dans Intégrations API, renseignez une URL et un secret. Affreta envoie alors un POST JSON à chaque événement :
| Événement | Déclencheur |
|---|---|
offer.received | un transporteur a déposé un prix |
offer.declined | un transporteur a décliné |
ping | test manuel depuis l'app |
Corps :
{
"event": "offer.received",
"created_at": "2026-09-18T09:12:40.000Z",
"data": { "request_id": "…", "transporteur": "…", "price_eur": 512, "delai_jours": 2 }
}
Vérifier la signature
Chaque requête porte les en-têtes x-affreta-event et x-affreta-signature. La signature est un HMAC-SHA256 du corps brut avec votre secret, préfixé de sha256=. Vérifiez-la avant de traiter l'événement :
// Node.js
import crypto from "crypto";
const sig = "sha256=" + crypto
.createHmac("sha256", WEBHOOK_SECRET)
.update(rawBody)
.digest("hex");
if (sig !== req.headers["x-affreta-signature"]) return res.status(401).end();
Email → demande (entrant)
Chaque organisation dispose d'une URL d'ingestion (visible dans l'application → Intégrations API → « Email → demande »). Tout email qui lui est transmis en POST devient un brouillon de demande pré-rempli : référence, date d'enlèvement, adresses, colis, poids et volume sont extraits du sujet et du corps ; le texte intégral est conservé dans les notes. Compatible Resend Receiving (webhook email.received), Zapier (Email Parser), Make (Mailhook), n8n (Email Trigger) ou tout appel HTTP.
curl -X POST "https://app.affreta.com/api/public/inbound/VOTRE_JETON" \ -H "Content-Type: application/json" \ -d '{ "from": "Client Démo <achats@client.fr>", "subject": "Transport palettes réf CMD-10482", "text": "Enlèvement : 12/11/2026 à Lyon 69007. Livraison : Nantes 44000. 12 palettes, 3200 kg." }'
Réponse (HTTP 201) : { "ok": true, "id": "…", "statut": "brouillon", "extracted": { … } }. Sans date détectée, l'enlèvement est posé à J+2 ouvrés et signalé « à confirmer ». Un GET sur l'URL vérifie la validité du jeton.
Erreurs
Les erreurs renvoient un JSON { "error": "…" } avec un statut HTTP : 400 (requête invalide), 401 (clé absente/invalide), 403 (scope insuffisant), 500 (erreur serveur).
Intégration ERP / WMS
Il n'existe pas de connecteur ERP « clé en main » : l'intégration se fait via cette API REST et ces webhooks, câblés à votre système par votre intégrateur (directement, ou via un middleware type Make/n8n). Des connecteurs dédiés peuvent être développés au cas par cas — écrivez-nous à hello@valkode.fr.