Pour commencer
Le responsable de votre société crée une clé dans le portail : Mon profil → Connexion à votre ERP ou boutique (API). La clé complète n'est affichée qu'une seule fois.
| Clé | Usage |
|---|---|
usk_test_… | Développement : de vrais prix, mais aucun envoi réel et aucune facturation. |
usk_live_… | Envois réels, possibles dès l'ouverture d'Uniship (début décembre 2026). Avant, la création d'envoi répond 409 portal_closed. |
Adresse de base : https://portail.uniship.be/api/v1. Authentification : en-tête Authorization: Bearer <votre clé>.
curl https://portail.uniship.be/api/v1/ping \
-H "Authorization: Bearer usk_test_…"
1. Demander un prix
Chaque offre est valable 15 minutes et ne sert qu'à un seul envoi. Les prix sont en euros, hors TVA, carburant inclus.
curl -X POST https://portail.uniship.be/api/v1/offers \
-H "Authorization: Bearer usk_test_…" -H "Content-Type: application/json" \
-d '{
"originCountry": "BE", "originZip": "7170",
"destCountry": "FR", "destZip": "75001",
"kind": "parcel",
"parcels": [ { "weight": 5, "length": 40, "width": 30, "height": 20 } ]
}'
La réponse contient la liste offers : offerId, carrier, label, price, transitMin / transitMax (jours ouvrés), les suppléments éventuels (fees) et les options de livraison (options).
2. Créer l'envoi
curl -X POST https://portail.uniship.be/api/v1/shipments \
-H "Authorization: Bearer usk_test_…" -H "Content-Type: application/json" \
-H "Idempotency-Key: CMD-1001" \
-d '{
"offerId": "…", "optionId": "none", "reference": "CMD-1001",
"sender": { "name": "Ma société", "address": "Rue de l'Exemple 1", "zip": "7170", "city": "Manage", "country": "BE", "phone": "…", "email": "…" },
"recipient": { "name": "Marie Martin", "address": "12 rue de Rivoli", "zip": "75001", "city": "Paris", "country": "FR" }
}'
Avec Idempotency-Key, un nouvel essai après une coupure réseau renvoie le même envoi sans en créer un second (valable 48 h). Hors Union européenne, ajoutez l'objet customs (nature, valeur et origine des marchandises, numéros fiscaux).
3. Étiquette et suivi
# Détail et suivi
curl https://portail.uniship.be/api/v1/shipments/{id} -H "Authorization: Bearer …"
# Étiquette en PDF
curl "https://portail.uniship.be/api/v1/shipments/{id}/label?format=pdf" -H "Authorization: Bearer …" -o etiquette.pdf
Tant que l'étiquette n'est pas prête, la réponse est 409 : réessayez un peu plus tard, ou attendez le webhook.
Toutes les routes
| Méthode et chemin | Rôle |
|---|---|
GET /v1/ping | Tester la clé |
POST /v1/offers | Demander des prix (30 par minute) |
POST /v1/shipments | Créer un envoi depuis une offre (60 par minute) |
GET /v1/shipments | Lister vos envois ; filtres status, reference ; pagination startAfter |
GET /v1/shipments/{id} | Lire un envoi et son suivi |
GET /v1/shipments/{id}/label | Étiquette (JSON base64 ou PDF) |
Lecture : 120 requêtes par minute et par clé. En cas de dépassement : 429 avec l'en-tête Retry-After. Erreurs : {"error":{"code":"…","message":"…"}}.
Statuts : pending, label_generated, picked_up, in_transit, out_for_delivery, delivered, exception, cancelled.
Télécharger la spécification OpenAPI (importable dans Postman, Insomnia ou Swagger).
Webhooks
Déclarez une adresse HTTPS dans le portail (Mon profil → Notifications automatiques). Uniship envoie un POST JSON à chaque création d'envoi (shipment.created) et à chaque changement de statut (shipment.status_changed).
{ "id": "evt_…", "type": "shipment.status_changed", "createdAt": "2026-12-01T09:30:00.000Z",
"data": { "id": "…", "reference": "CMD-1001", "status": "in_transit", "previousStatus": "picked_up", "trackingNumber": "…" } }
Vérifier la signature
En-tête Uniship-Signature: t=<secondes>,v1=<hex>, où v1 est le HMAC-SHA256 de "<t>.<corps brut>" avec votre secret. Refusez un message dont t date de plus de 5 minutes.
const crypto = require('crypto');
function verify(rawBody, header, secret) {
const p = Object.fromEntries(header.split(',').map(x => x.split('=')));
if (Math.abs(Date.now() / 1000 - Number(p.t)) > 300) return false;
const exp = crypto.createHmac('sha256', secret).update(p.t + '.' + rawBody).digest('hex');
return crypto.timingSafeEqual(Buffer.from(exp), Buffer.from(p.v1));
}
- Répondez
2xxen moins de 10 secondes. Sinon, 8 tentatives : après 1 min, 5 min, 15 min, 1 h, 3 h, 6 h puis 12 h. - Un message peut arriver plusieurs fois et dans le désordre : dédupliquez avec
id, ordonnez avecdata.updatedAt. - Adresses
https://publiques uniquement (port 443). 5 adresses actives par société. Un bouton « Envoyer un essai » existe dans le portail.
Sécurité et bonnes pratiques
- Une clé est un mot de passe : gardez-la côté serveur, jamais dans une page web ou une application mobile.
- Une clé ne voit que les envois de votre société. Elle peut être révoquée à tout moment dans le portail.
- Pas d'ERP en vue ? Voir les autres moyens de connexion (import de fichier CSV, plugins en préparation).
- Une question ou un besoin particulier : écrivez-nous.
