L'accès API est disponible uniquement sur les plans Gold et Platinium.
Rendez-vous dans Paramètres → Abonnement pour upgrader.
{/* Step 1 */}
1
Obtenir votre clé API
Dans le dashboard, rendez-vous dans Paramètres → Clés API, puis cliquez sur Créer une clé.
La clé complète vous sera montrée une seule fois — conservez-la immédiatement.
Format de la clé :
{/* Step 2 */}
2
Faire votre première requête
Passez la clé dans l'en-tête X-API-Key :
{/* Step 3 */}
3
Lire la réponse
Toutes les réponses sont en JSON. En cas de succès :
En cas d'erreur :
Étapes suivantes
{[
{ id: 'authentication', label: 'Gérer vos clés API', desc: 'Créer, lister et révoquer des clés' },
{ id: 'bookings', label: 'Créer un booking', desc: 'Réservez du fret maritime via l\'API' },
{ id: 'rates', label: 'Rechercher des tarifs', desc: 'Comparez les tarifs en temps réel' },
{ id: 'errors', label: 'Gestion des erreurs', desc: 'Tous les codes d\'erreur expliqués' },
].map(item => (
))}
L'API Xpeditis utilise des clés API pour authentifier les requêtes.
Transmettez votre clé dans l'en-tête X-API-Key de chaque requête.
Vos clés API sont confidentielles. Ne les partagez jamais dans du code public, des dépôts Git ou des forums.
En cas de compromission, révoquez immédiatement la clé depuis le dashboard.
Format de la clé
Toutes les clés Xpeditis commencent par xped_live_ suivi de 64 caractères hexadécimaux :
Utilisation
Header HTTP
Passez votre clé dans l'en-tête X-API-Key :
Exemples par langage
Endpoints de gestion
Ces endpoints nécessitent une authentification par token JWT (connexion via le dashboard) et non une clé API.
Créer une clé
" \\
-H "Content-Type: application/json" \\
-d '{
"name": "Intégration ERP Production",
"expiresAt": "2027-01-01T00:00:00.000Z"
}'`}
/>
Le champ fullKey est retourné une seule fois.
Stockez-le immédiatement dans un gestionnaire de secrets.
Sécurité
Stockage recommandé
Rotation des clés
Effectuez une rotation régulière (tous les 90 jours recommandé) : créez une nouvelle clé, migrez votre système,
puis révoquez l'ancienne.
status, 'string', 'Filtrer par statut (draft, confirmed, in_transit, delivered, cancelled)'],
[page, 'number', 'Numéro de page (défaut: 1)'],
[limit, 'number', 'Résultats par page (défaut: 20, max: 100)'],
[origin, 'string', 'Code port d\'origine (ex: FRLEH)'],
[destination, 'string', 'Code port de destination (ex: CNSHA)'],
]}
/>
Créer un booking
Statuts d'un booking
draft, 'Réservation créée, non confirmée'],
[pending_confirmation, 'En attente de confirmation du transporteur'],
[confirmed, 'Confirmée par le transporteur'],
[in_transit, 'Expédition en cours'],
[delivered, 'Livraison confirmée'],
[cancelled, 'Annulée'],
]}
/>
);
}
// ─── Section: Rates ───────────────────────────────────────────────────────────
function RatesSection() {
return (
Rechercher des tarifs
origin, '✅', 'Code port d\'origine (UN/LOCODE, ex: FRLEH)'],
[destination, '✅', 'Code port de destination (ex: CNSHA)'],
[containerType, '✅', 'Type de conteneur: 20GP, 40GP, 40HC, 45HC, 20FR, 40FR'],
[departureDate, '❌', 'Date souhaitée de départ (YYYY-MM-DD)'],
[sortBy, '❌', 'Tri: price_asc | price_desc | transit_time'],
]}
/>
Les tarifs sont mis en cache pendant 15 minutes. Au-delà, une nouvelle recherche est effectuée
auprès des transporteurs en temps réel.
Codes de ports (UN/LOCODE)
Les ports sont identifiés par le code standard UN/LOCODE (5 caractères).
Le rate limiting est appliqué par utilisateur (ID de l'utilisateur associé à la clé API).
En-têtes de réponse
Chaque réponse inclut des en-têtes pour suivre votre consommation :
Bonnes pratiques
{[
{ icon: Clock, title: 'Exponential backoff', desc: 'En cas de 429, attendez avant de réessayer (1s, 2s, 4s, 8s…).' },
{ icon: CheckCircle2, title: 'Mise en cache', desc: 'Cachez les résultats côté client pour éviter les appels redondants. Les tarifs restent valides 15 minutes.' },
{ icon: ShieldCheck, title: 'Une clé par service', desc: 'Utilisez des clés séparées par service ou environnement pour un meilleur suivi et une révocation ciblée.' },
].map((item, i) => (
{item.title}
{item.desc}
))}
);
}
// ─── Section map ──────────────────────────────────────────────────────────────
function SectionContent({
activeSection,
onNavigate,
}: {
activeSection: string;
onNavigate: (id: string) => void;
}) {
switch (activeSection) {
case 'home': return ;
case 'quickstart': return ;
case 'authentication': return ;
case 'bookings': return ;
case 'rates': return ;
case 'organizations': return ;
case 'endpoints': return ;
case 'errors': return ;
case 'rate-limiting': return ;
default: return ;
}
}
// ─── Main Page ────────────────────────────────────────────────────────────────
function DocsPageContent() {
const searchParams = useSearchParams();
const router = useRouter();
const [activeSection, setActiveSection] = useState(searchParams.get('section') ?? 'home');
const [searchQuery, setSearchQuery] = useState('');
const [sidebarOpen, setSidebarOpen] = useState(false);
const navigate = (id: string) => {
setActiveSection(id);
router.replace(`/dashboard/docs?section=${id}`, { scroll: false });
setSidebarOpen(false);
window.scrollTo({ top: 0, behavior: 'smooth' });
};
// Filter nav based on search
const filteredSections = DOC_SECTIONS.map(section => ({
...section,
items: section.items.filter(item =>
item.label.toLowerCase().includes(searchQuery.toLowerCase())
),
})).filter(s => s.items.length > 0);
const Sidebar = () => (