Endpoints · Tarifs
Calculer un tarif
Obtenez le prix réel de votre compte avant de créer un bordereau.
Calcule un prix avec la logique tarifaire réelle de votre compte. Requiert le scope write (méthode POST).
# Compte de reference de TOUS les exemples de cette page :
# pricePerKg = 9 EUR (forfait jusqu'a 4 kg), minimumPrice = 7 EUR.
# Un compte sans pricePerKg (null) paierait 7 EUR le meme colis. Le tarif
# depend de VOTRE grille : appelez /rates, ne recopiez pas le chiffre.
curl -X POST "https://api.arelpro.com/pro/api/v1/rates" \
-H "Authorization: Bearer sk_live_VOTRE_CLE" \
-H "X-Client-Id: VOTRE_CLIENT_ID" \
-H "Content-Type: application/json" \
-d '{ "weight": 2.5, "deliveryAddress": { "postalCode": "75001", "city": "Paris", "countryCode": "FR" } }'Réponse :
{
"success": true,
"eligible": true,
"coverageChecked": true,
"rate": {
"price": 9,
"currency": "EUR",
"weightInKg": 2.5,
"minimumPrice": 7,
"pricePerKg": 9,
"pricingModel": "professional_tiered",
"scheduledDelivery": null
}
}Le tarif est sous la clé rate : il n'y a pas de champ price à la racine. Le poids vous revient sous le nom weightInKg, et non weight comme dans votre requête.
Compte de référence de ces exemples : pricePerKg: 9, minimumPrice: 7. Les prix affichés ici n'ont de sens que pour cette grille — un compte sans pricePerKg paierait 7 € le même colis de 2,5 kg. Si un autre document Arel montre un prix différent pour ce colis, c'est qu'il illustre un autre compte. Seul l'appel à /rates indique votre prix.
weight (ou parcelDetails.weight) suffit pour un devis de prix sans adresse : la réponse porte alors eligible: null et coverageChecked: false. Cela ne confirme pas que la destination est desservie. pricingModel vaut scheduled_slot, professional_tiered ou professional_minimum, selon la grille de votre compte.
Vérifier la destination avant de proposer AREL
Envoyez deliveryAddress.postalCode, deliveryAddress.city et deliveryAddress.countryCode. Les destinations disponibles dépendent des zones autorisées par AREL sur votre compte marchand. Le code postal seul peut désigner plusieurs communes.
Une destination refusée renvoie HTTP 200 avec eligible: false, rate: null, un code error et une explication reason. Masquez AREL dans ce cas. Si la vérification est indisponible (HTTP 503), réessayez et ne proposez pas AREL sans confirmation.
Un devis ne réserve pas une zone : la destination est vérifiée à nouveau à la création du bordereau.
{
"success": true,
"eligible": false,
"error": "ZONE_NON_AUTORISEE",
"reason": "Cette destination ne fait pas partie des zones autorisées sur votre compte.",
"rate": null
}Options de livraison proposées à vos acheteurs
Cet appel authentifié (scope read) renvoie le catalogue de votre compte sous deliveryOptions. AREL configure les horaires et leurs libellés. Vous gardez la main sur le prix facturé à votre acheteur : rate.price est le prix de votre prestation AREL, indépendant de votre prix de vente au checkout.
Sans créneau actif, mode vaut standard et services contient une seule option : id: "standard", serviceCode: "AREL_STANDARD", nom « Livraison AREL », deliveryWindow: null. N'affichez alors aucun horaire. Avec des créneaux actifs, mode vaut slots et chaque service contient sa fenêtre officielle : début, fin, spansNextDay et fuseau Europe/Paris.
Les devis éligibles renvoient également ce catalogue à la racine, à côté de rate. Après vérification de la destination, proposez ses services et conservez l'identifiant choisi ainsi que deliveryOptions.revision. À la création du bordereau, transmettez les deux champs deliveryOptionId et deliveryOptionsRevision. Le serveur contrôle ce choix et enregistre la fenêtre officielle sur le bordereau.
Actualiser les choix si les horaires changent
Un HTTP 422 avec DELIVERY_OPTIONS_CHANGED ou DELIVERY_OPTION_UNAVAILABLEexige de recharger le catalogue puis de faire confirmer un nouveau choix. Ne remplacez jamais automatiquement un créneau retiré par une livraison sans horaire.
Une indisponibilité du catalogue (HTTP 503, DELIVERY_OPTIONS_UNAVAILABLE) ne signifie pas qu'aucun créneau n'est configuré. Réessayez avant de proposer AREL.
Ces options ne programment pas un enlèvement et n'appliquent pas la grille des envois programmés décrite ci-dessous. Ne les combinez pas avec scheduledDate ou timeSlot.
pricePerKg est un forfait, pas un prix au kilo
Malgré son nom, c'est un forfait qui couvre le colis jusqu'à 4 kg ; au-delà s'ajoutent 1,17 € par kilo supplémentaire. Ne le multipliez pas par le poids : à 2,5 kg avec pricePerKg: 9, le prix est 9 €, pas 22,50 €.
Si votre compte n'a pas de pricePerKg (valeur null), le modèle est professional_minimum et le prix vaut minimumPrice, quel que soit le poids.
Ne réimplémentez pas ce calcul. Il évolue avec votre grille commerciale ; POST /rates est la seule source de vérité, et c'est le même code qui facture à la création.
Un créneau programmé change de grille tarifaire
Dès que vous passez scheduledDate + timeSlot, votre forfait pricePerKg n'est plus utilisé. Le prix repart d'une grille au poids :
- base =
poids × 7 €, avec un plancher de 7 € ; - + 3 € si le créneau commence avant 9h ou à 18h et après ;
- + 5 € si la date tombe un samedi ou un dimanche.
À 2,5 kg : 9 € en express (forfait), mais 17,50 € programmé en semaine à 14h — et 25,50 € un samedi à 19h. Le créneau n'est pas une option gratuite : sur un colis lourd, l'écart se creuse encore.
pricePerKg reste renvoyé dans la réponse en scheduled_slot : c'est le réglage de votre compte, pas le prix appliqué. Seul price fait foi. Ces surcoûts ne touchent que les envois programmés : un express créé un samedi ne paie pas les 5 €.
scheduledDelivery vaut null pour un envoi express. Si vous passez un créneau, il porte trois champs : date, timeSlot (le libellé normalisé) et slotId — l'id du créneau configuré sur votre compte, ou null si vous avez fourni un libellé libre du type 14h-16h.
Les deux champs ne peuvent pas être renseignés arbitrairement en même temps. Un créneau de votre compte n'est reconnu que par son id ou son libellé exact. Deux branches, deux résultats :
- vous envoyez
"14h-16h"(libellé libre) →timeSlot: "14h-16h",slotId: null; - vous envoyez
"s1"(un id de votre compte) →slotId: "s1", ettimeSlotvous revient réécrit avec le libellé du créneau (par ex."Matin") — pas la valeur que vous aviez envoyée.
Ne comparez donc jamais le timeSlot renvoyé à celui que vous avez envoyé pour vérifier le succès : sur un id, l'égalité est fausse alors que tout est correct.