Guide du développeur — Webhooks ShipTime
Avec l’API ShipTime, vous pouvez simplifier vos processus d’expédition, automatiser vos flux de travail et intégrer les fonctionnalités de ShipTime directement à votre propre plateforme.
ShipTime prend également en charge les webhooks, ce qui permet à votre application de recevoir des mises à jour d’expédition en temps réel dès qu’elles surviennent.
Avant de commencer
Avant d’intégrer les webhooks ShipTime, assurez-vous d’avoir :
- un compte ShipTime avec accès à l’API;
- un point de terminaison HTTPS accessible publiquement;
- un emplacement sécurisé pour stocker votre secret de webhook.
Vous n’avez pas encore de compte ShipTime? Inscrivez-vous à app.shiptime.com.
Vous avez besoin d’un accès à l’API? Consultez la documentation de l’API ShipTime pour savoir comment obtenir vos identifiants API.
Contenu
- Aperçu
- Démarrage rapide
- Types d’événements
- API des abonnements
- Authentification
- Créer un abonnement
- Lister les abonnements
- Obtenir un abonnement
- Mettre à jour un abonnement
- Supprimer un abonnement
- Recevoir les événements
- Format de la charge utile
- En-têtes de livraison
- Vérifier les signatures
- Politique de livraison et de nouvelle tentative
- Bonnes pratiques
Aperçu
Plutôt que d’interroger régulièrement l’API de suivi pour vérifier si le statut d’un envoi a changé, vous pouvez enregistrer un webhook une seule fois. Chaque fois que le statut de suivi d’un envoi change, ShipTime envoie à votre point de terminaison une requête HTTP POST signée contenant une charge utile JSON.
Une intégration par webhook comporte deux volets :
- Gérer les abonnements aux webhooks — Utilisez l’API Webhook Subscriptions (
/rest/webhooks) pour enregistrer et gérer les points de terminaison HTTPS qui recevront les événements webhook. Ces points de terminaison utilisent la même méthode d’authentification que le reste de l’API REST ShipTime. - Recevoir les événements webhook — Implémentez votre propre point de terminaison HTTPS afin de recevoir les requêtes webhook, vérifier la signature de chaque requête et traiter la charge utile de l’événement.
Démarrage rapide
Suivez ces trois étapes pour créer une intégration webhook fonctionnelle.
1 · Enregistrer votre point de terminaison
# Uses your ShipTime API bearer token curl -X POST https://api.shiptime.com/rest/webhooks \ -H "Authorization: Bearer $SHIPTIME_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "url": "https://hooks.yourapp.com/shiptime", "eventType": ["shipment.status_changed"], "description": "Shipment status change listener" }'
La réponse 201 Created contient un secret de webhook. Conservez cette valeur dans un emplacement sécurisé. Elle n’est retournée qu’une seule fois et est requise pour vérifier toutes les futures requêtes webhook.
2 · Recevoir et vérifier
Implémentez un point de terminaison HTTPS qui :
- accepte les requêtes HTTP POST;
- lit le corps brut de la requête;
- vérifie l’en-tête
X-ShipTime-Signature; - retourne une réponse HTTP
200 OKaprès une vérification réussie.
La vérification de la signature est décrite en détail dans la section Vérifier les signatures.
3 · Créer un envoi
Créez un envoi à l’aide de l’API ShipTime comme d’habitude. À mesure que les transporteurs numérisent l’envoi, ShipTime transmet automatiquement les événements webhook à votre point de terminaison enregistré en temps réel.
Types d’événements
Le tableau eventType d’un abonnement webhook détermine quels événements votre point de terminaison reçoit. Omettez le champ eventType, ou fournissez un tableau vide, pour recevoir tous les événements pris en charge.
| Type d’événement | Description | Détails de la charge utile |
|---|---|---|
shipment.status_changed |
Envoyé lorsqu’un envoi change de statut, depuis sa création (PENDING) jusqu’aux transitions PENDING → IN_TRANSIT, IN_TRANSIT → DELIVERED ou à son annulation. | Comprend le statut précédent, le nouveau statut et le numéro de suivi. |
shipment.tracking_updated |
Envoyé pour chaque balayage de suivi du transporteur, y compris les mises à jour qui ne modifient pas le statut de l’envoi. | Comprend toutes les données de shipment.status_changed, ainsi que l’historique complet des balayages dans tracking_events. |
Abonnez-vous à shipment.tracking_updated si vous avez besoin d’une visibilité complète sur chaque événement de suivi.
Abonnez-vous à shipment.status_changed si vous avez seulement besoin des principales étapes du suivi.
Comme shipment.tracking_updated contient toutes les données de shipment.status_changed, il n’est généralement pas nécessaire de s’abonner aux deux.
Valeurs de statut d’expédition
Les charges utiles webhook peuvent contenir les valeurs de statut suivantes :
DEFERRED PENDING MANIFESTED IN_TRANSIT DELIVERED REFUND_REQUESTED CANCELLED EXCEPTION
API des abonnements
Utilisez l’API Webhook Subscriptions pour créer, récupérer, mettre à jour et supprimer des abonnements webhook.
Tous les points de terminaison de gestion des abonnements se trouvent sous :
/rest/webhooks
Authentification
Tous les points de terminaison /rest/webhooks utilisent la même méthode d’authentification que le reste de l’API REST ShipTime.
Incluez un Bearer JWT dans l’en-tête Authorization. Votre jeton doit inclure le rôle RESTAPI. Tous les identifiants API standards l’incluent.
Authorization: Bearer <your-jwt>
Créer un abonnement
Crée un nouvel abonnement webhook.
Point de terminaison
POST /rest/webhooks
Champs de la requête
| Champ | Type | Obligatoire | Description |
|---|---|---|---|
url |
string | oui | Point de terminaison HTTPS qui recevra les événements webhook. Maximum de 512 caractères. |
eventType |
string[] | non | Événements auxquels s’abonner. Omettez le champ ou fournissez un tableau vide pour recevoir tous les événements. |
description |
string | non | Libellé facultatif permettant d’identifier l’abonnement. |
Réponse
201 Created
{ "id": 41, "url": "https://hooks.yourapp.com/shiptime", "secret": "a3f8c2d1e9b7...d491", "active": true, "eventType": ["shipment.status_changed"], "description": "Shipment status change listener", "createdAt": 1748908800000, "updatedAt": null }
Le secret est retourné une seule fois lors de la création de l’abonnement. Conservez-le en lieu sûr, car il est requis pour vérifier les requêtes webhook entrantes et ne peut pas être récupéré ultérieurement.
Rotation du secret
Le réenregistrement de la même URL à l’aide d’une nouvelle requête POST génère un nouveau secret et réactive l’abonnement s’il avait été désactivé.
Utilisez cette méthode pour remplacer un secret compromis. Pour modifier les champs d’un abonnement sans générer de nouveau secret, utilisez plutôt le point de terminaison Mettre à jour un abonnement.
Lister les abonnements
Retourne tous les abonnements webhook associés à votre compte, y compris les abonnements actifs et inactifs.
Point de terminaison
GET /rest/webhooks
Retourne un tableau d’objets d’abonnement. Le secret n’est jamais inclus dans les réponses de type liste ou consultation.
Réponse
200 OK
[ { "id": 41, "url": "https://hooks.yourapp.com/shiptime", "active": true, "eventType": ["shipment.status_changed"], "description": "Shipment status change listener", "createdAt": 1748908800000, "updatedAt": 1749012400000 } ]
Obtenir un abonnement
Retourne un seul abonnement webhook.
Point de terminaison
GET /rest/webhooks/{id}
Réponse
Retourne l’objet d’abonnement.
Si l’abonnement est introuvable, l’API retourne :
404 Not Found
Mettre à jour un abonnement
Met à jour un abonnement webhook existant sans effectuer de rotation du secret.
Point de terminaison
PUT /rest/webhooks/{id}
| Champ | Type | Obligatoire | Description |
|---|---|---|---|
url |
string | oui | URL du point de terminaison. |
eventType |
string[] | non | Remplace le filtre d’événements existant. |
description |
string | non | Met à jour le libellé de l’abonnement. |
active |
boolean | non | Définissez la valeur à true pour réactiver un abonnement désactivé. Omettez le champ pour conserver la valeur actuelle. |
Réponse
200 OK
Retourne l’objet d’abonnement mis à jour.
Supprimer un abonnement
Effectue une suppression logique d’un abonnement webhook.
Point de terminaison
DELETE /rest/webhooks/{id}
Réponse
204 No Content
L’abonnement est marqué comme inactif (active = false) et les livraisons webhook cessent immédiatement.
Pour réactiver l’abonnement :
- mettez à jour l’abonnement avec
PUTet définissez"active": true; ou - réenregistrez la même URL avec
POST.
Recevoir les événements
Une fois l’abonnement webhook configuré, ShipTime transmet les événements webhook sous forme de requêtes HTTP POST au point de terminaison enregistré.
Chaque requête contient une charge utile JSON décrivant l’événement.
Format de la charge utile
Chaque livraison webhook contient une enveloppe d’événement JSON.
shipment.status_changed
{ "id": "b3d9a1f2-4c8e-4a1b-9f3d-2e7a6b5c8d9e", "type": "shipment.status_changed", "shipment_id": "10001", "occurred_at": "2026-04-29T14:02:00Z", "data": { "previous_status": "PENDING", "new_status": "IN_TRANSIT", "tracking_number": "1Z999AA10123456784" } }
Champs de l’événement
| Champ | Description |
|---|---|
id |
Identifiant unique de l’événement. Utilisez cette valeur comme clé de déduplication, car le même événement peut être livré plus d’une fois. |
type |
Type d’événement webhook. |
shipment_id |
Identifiant d’envoi ShipTime. Utilisez-le pour associer l’événement à l’envoi créé avec l’API ShipTime. |
occurred_at |
Horodatage UTC ISO-8601 indiquant le moment où l’événement s’est produit. |
data.previous_status |
Statut avant la transition. Peut être null pour le premier événement. |
data.new_status |
Statut de l’envoi après la transition. |
data.tracking_number |
Numéro de suivi du transporteur. |
shipment.tracking_updated
Pour les événements shipment.tracking_updated, l’objet data comprend également l’historique des balayages de suivi du transporteur dans le tableau tracking_events.
"data": { "previous_status": "IN_TRANSIT", "new_status": "IN_TRANSIT", "tracking_number": "1Z999AA10123456784", "tracking_events": [ { "status": "IN_TRANSIT", "description": "Out for delivery", "location": "Toronto, ON", "occurred_at": "2026-04-29T13:30:00Z" }, { "status": "IN_TRANSIT", "description": "Arrived at facility", "location": "Toronto Hub, ON", "occurred_at": "2026-04-29T11:00:00Z" } ] }
Preuve de livraison
Lorsqu’un envoi atteint le statut DELIVERED et que le transporteur fournit des renseignements de preuve de livraison, l’objet data.proof_of_delivery est inclus dans la charge utile.
"proof_of_delivery": { "location": "Front door", "signed_by": "J. SMITH", "occurred_at": "2026-04-29T14:02:00Z" }
En-têtes de livraison
Chaque requête webhook contient les en-têtes HTTP suivants :
| En-tête | Exemple | Rôle |
|---|---|---|
X-ShipTime-Signature |
t=1748908800,v1=a3f8c2… |
Horodatage et signature HMAC-SHA256 utilisés pour vérifier la requête. |
X-ShipTime-Event-Id |
b3d9a1f2-4c8e-… |
Correspond à l’identifiant de l’événement. Utilisez-le comme clé d’idempotence. |
X-ShipTime-Delivery-Attempt |
0 |
Numéro de tentative de livraison, indexé à partir de zéro. |
X-ShipTime-Event-Type |
shipment.status_changed |
Indication du type d’événement. Voir la remarque ci-dessous. |
User-Agent |
ShipTime-Webhooks/1 |
Identifie ShipTime comme expéditeur. |
Remarque : Déterminez le type d’événement webhook à partir du champ type de la charge utile.
L’en-tête X-ShipTime-Event-Type retourne actuellement toujours shipment.status_changed, même pour les événements shipment.tracking_updated. Considérez cet en-tête uniquement comme une indication.
Vérifier les signatures
Comme votre point de terminaison est accessible publiquement, vous devez vérifier que chaque requête webhook a bien été envoyée par ShipTime.
Chaque requête webhook est signée à l’aide du secret de votre abonnement et de l’algorithme HMAC-SHA256.
Format de la signature
L’en-tête X-ShipTime-Signature utilise le format suivant :
t=<unix-seconds>,v1=<hex-hmac>
Où :
test l’horodatage Unix en secondes;v1est la signature HMAC-SHA256.
Processus de vérification
Pour vérifier une requête webhook :
- Analysez les valeurs
tetv1de l’en-têteX-ShipTime-Signature. - Construisez le message signé en concaténant :
t;- un caractère littéral
.; - le corps brut de la requête — ne resérialisez pas le JSON.
- Calculez le condensat HMAC-SHA256 à l’aide de votre secret de webhook.
- Comparez le condensat calculé à
v1à l’aide d’une comparaison en temps constant. - Rejetez la requête si l’horodatage diffère de l’heure actuelle de plus de 300 secondes afin de vous protéger contre les attaques par rejeu.
Construction du message
message = t + "." + raw_request_body expected = hex(HMAC-SHA256(secret, message)) valid = constantTimeEquals(expected, v1)
Exemple : Node.js (Express)
const crypto = require('crypto'); // Capture the RAW body for verification app.use(express.raw({ type: 'application/json' })); app.post('/shiptime', (req, res) => { const sig = req.get('X-ShipTime-Signature') || ''; const { t, v1 } = Object.fromEntries( sig.split(',').map(p => p.split('=')) ); if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return res.sendStatus(400); const msg = t + '.' + req.body; const expected = crypto .createHmac('sha256', SECRET) .update(msg) .digest('hex'); const ok = crypto.timingSafeEqual( Buffer.from(expected), Buffer.from(v1 || '') ); if (!ok) return res.sendStatus(401); const event = JSON.parse(req.body); // Handle event.type // Deduplicate using event.id res.sendStatus(200); });
Exemple : Python (Flask)
import hmac, hashlib, timefrom flask import request, abortdef verify(): sig = request.headers.get('X-ShipTime-Signature', '') parts = dict( p.split('=', 1) for p in sig.split(',') if '=' in p ) t, v1 = parts.get('t'), parts.get('v1') if not t or abs(time.time() - int(t)) > 300: abort(400) raw = request.get_data() msg = t.encode() + b'.' + raw expected = hmac.new( SECRET.encode(), msg, hashlib.sha256 ).hexdigest() if not hmac.compare_digest(expected, v1 or ''): abort(401)# In the route:# verify()# event = request.get_json()# handle event['type']# dedupe on event['id']
Exemple : Java
Mac mac = Mac.getInstance("HmacSHA256"); mac.init(new SecretKeySpec(secret.getBytes(UTF_8), "HmacSHA256")); byte[] out = mac.doFinal((t + "." + rawBody).getBytes(UTF_8)); String expected = Hex.encodeHexString(out); boolean ok = MessageDigest.isEqual( expected.getBytes(UTF_8), v1.getBytes(UTF_8) );
Important : Vérifiez toujours la signature avant de traiter la charge utile du webhook. Rejetez les requêtes dont la signature est invalide ou dont l’horodatage est trop ancien avant d’exécuter toute logique métier.
Politique de livraison et de nouvelle tentative
ShipTime s’attend à ce que votre point de terminaison confirme la réception des livraisons webhook en retournant une réponse HTTP 2xx.
Si une tentative de livraison échoue, ShipTime effectue automatiquement de nouvelles tentatives selon un calendrier de délai exponentiel.
Livraison réussie
Une livraison webhook est considérée comme réussie lorsque votre point de terminaison retourne un code d’état HTTP 2xx.
Dès qu’une livraison réussit, aucune autre tentative n’est effectuée.
Calendrier des nouvelles tentatives
| Tentative | Délai |
|---|---|
| 1 | 5 minutes |
| 2 | 30 minutes |
| 3 | 2 heures |
| 4 | 5 heures |
| 5 | 10 heures |
| 6–8 | 24 heures |
Après la dernière tentative, l’événement est marqué comme définitivement échoué et aucune tentative supplémentaire n’est effectuée.
Conditions de nouvelle tentative
Une nouvelle tentative est effectuée lorsque :
- votre point de terminaison retourne un code HTTP autre que
2xx; - la requête expire;
- une erreur réseau empêche la livraison de la requête.
Livraisons en double
Les points de terminaison webhook doivent être idempotents.
Même si ShipTime effectue des nouvelles tentatives uniquement lorsque nécessaire, le même événement peut être livré plus d’une fois. Utilisez l’id de l’événement pour détecter et ignorer les événements en double.
Important : Considérez toujours les livraisons webhook comme pouvant survenir au moins une fois. Votre application doit pouvoir gérer les doublons en toute sécurité en stockant les identifiants d’événements déjà traités et en ignorant ceux qui ont déjà été reçus.
Temps de réponse
Retournez une réponse HTTP indiquant la réussite le plus rapidement possible.
Si un traitement supplémentaire est requis, confirmez d’abord la réception du webhook, puis effectuez le reste du traitement de façon asynchrone.
Abonnements en échec
Si un abonnement échoue à plusieurs reprises à recevoir les livraisons webhook, ShipTime peut désactiver l’abonnement afin de protéger les ressources du système.
Une fois le problème résolu, vous pouvez réactiver l’abonnement en le mettant à jour ou en enregistrant de nouveau la même URL.
Bonnes pratiques
- Vérifiez la signature de chaque webhook avant de traiter la requête.
- Utilisez HTTPS pour tous les points de terminaison webhook.
- Retournez rapidement une réponse
2xxet traitez les événements de façon asynchrone lorsque possible. - Traitez les livraisons webhook de façon idempotente en stockant les identifiants d’événements déjà traités et en ignorant les doublons.
- Protégez votre secret de webhook et effectuez immédiatement une rotation si vous soupçonnez qu’il a été compromis.
- Surveillez les livraisons échouées et réactivez les abonnements après avoir corrigé les problèmes.
- Abonnez-vous uniquement aux types d’événements dont vous avez besoin afin de réduire le traitement inutile.
Prochaines étapes
Vous êtes maintenant prêt à intégrer les webhooks ShipTime à votre application.
Une intégration typique suit les étapes suivantes :
- Créer un abonnement webhook.
- Stocker le secret retourné dans un emplacement sécurisé.
- Configurer votre point de terminaison pour recevoir les requêtes webhook.
- Vérifier la signature de la requête.
- Traiter l’événement webhook.
- Retourner une réponse HTTP
2xx. - Surveiller les livraisons et gérer les nouvelles tentatives au besoin.
Pour obtenir de l’aide supplémentaire, communiquez avec l’équipe de soutien technique ShipTime à techsupport@shiptime.com.