API Partenaire pour les transitaires
Soumettez des demandes d'approvisionnement pour le compte de vos clients, recevez des cotations chiffrées, téléchargez des preuves de paiement et recevez les mises à jour de statut via des webhooks signés, le tout en HTTPS avec une seule clé API.
Vue d'ensemble
L'API Partenaire permet à un transitaire ou à un partenaire d'approvisionnement tiers de créer des commandes dans notre plateforme par programmation. Chaque commande suit le même pipeline d'exécution que celles créées depuis notre interface, et le partenaire reçoit des notifications webhook à chaque changement d'état important.
https://kuaisourcing.com/api-backTous les endpoints ci-dessous sont relatifs à cette base.Authentification
Chaque requête doit inclure votre clé API dans l'en-tête x-api-key. La clé identifie le compte partenaire qui appelle, gardez-la secrète.
POST /api/partner/sourcing HTTP/1.1
Host: kuaisourcing.com
Content-Type: application/json
x-api-key: ks_live_yourkeyhere1234567890abcdefNe placez jamais la clé dans du code côté client et ne la commitez pas sur git. Traitez-la comme un mot de passe. Si elle est exposée, demandez à votre gestionnaire de compte de la régénérer, l'ancienne clé est révoquée immédiatement.
Cycle de vie d'une commande
Une commande passe par les états suivants. Le webhook order.status_changed se déclenche à chaque transition.
Statuts terminaux hors-parcours : Cancelled, Refunded, Order Rejected, OutOfStock.
Soumettre une demande d'approvisionnement
Une requête peut contenir plusieurs destinations. Chaque destination doit déclarer son transporteur, depuis notre catalogue ou auto-géré.
{
"productName": "Bluetooth Earbuds Pro",
"productImageUrl": "https://yourcdn.com/img.jpg",
"productURL": "https://supplier-page.example/product/123",
"category": "Electronics",
"targetMarket": "Africa",
"additionalNotes": "Need OEM packaging",
"airFreight": true,
"seaFreight": false,
"byTrain": false,
"expressDelivery": false,
"normalDelivery": true,
"domesticDelivery": "slow",
"shippingResponsibility": "kuai",
"destinations": [
{
"country": "Gabon",
"city": "Libreville",
"address": "1 Example Street",
"quantity": 50,
"variants": "[{\"color\":\"Black\",\"quantity\":30},{\"color\":\"White\",\"quantity\":20}]",
"service": "DHL",
"recipientName": "Jane Doe",
"contactNumber": "+241 00 00 00 00"
},
{
"country": "Tunisia",
"city": "Tunis",
"quantity": 30,
"service": "Other ...",
"customService": "Local forwarder name",
"recipientName": "John Doe",
"contactNumber": "+216 00 000 000",
"isCompanyService": false
}
]
}Champs de premier niveau
| Champ | Requis | Notes |
|---|---|---|
| productName | oui | Libellé court du produit |
| targetMarket | oui | ex. "Africa" |
| destinations | oui | Au moins une entrée. Chaque entrée doit avoir country + quantity. |
| airFreight / seaFreight / byTrain | un doit être vrai | Si airFreight est true, définissez aussi expressDelivery ou normalDelivery. |
| domesticDelivery | optionnel | "fast" ou "slow" (en Chine) |
| shippingResponsibility | optionnel | "kuai" / "service" / "self" |
| productImageUrl | optionnel | Doit être accessible. Téléversez d'abord via l'endpoint uploads pour plus de sûreté. |
Réponse · 201 Created
{
"success": true,
"data": {
"orderId": "9f5e2c3a-...",
"customOrderId": "KS0000",
"message": "Sourcing request submitted successfully"
}
}Utilisez orderId (UUID) pour les appels suivants. customOrderId (KS0001, KS0002, …) est le même identifiant séquentiel que celui affiché dans notre tableau de bord interne.
Lister vos commandes
| Paramètre | Défaut | Notes |
|---|---|---|
| status | (any) | Filtrer par statut exact (voir section cycle de vie) |
| details | true | false pour une charge utile plus légère (sans cotations / images / destinations) |
| page | 0 | Indexé à partir de zéro |
| size | 100 | Maximum 100 |
Renvoie une Page Spring de commandes (voir Récupérer une commande pour la structure).
Récupérer une commande
Les deux formes renvoient la même charge utile.
{
"success": true,
"data": {
"id": "9f5e2c3a-...",
"customOrderId": "KS0000",
"productName": "Bluetooth Earbuds Pro",
"status": "Unpaid",
"formCreationDate": "2026-05-10T08:14:32",
"lastUpdated": "2026-05-13T11:02:08",
"realImages": [
{ "id": "...", "image": "https://files.example.com/uploads/real-1.jpg", "addedAt": "2026-05-13T10:55:00" },
{ "id": "...", "image": "https://files.example.com/uploads/demo.mp4", "addedAt": "2026-05-13T11:00:00" }
],
"destinations": [
{
"id": "d4...",
"country": "Gabon",
"city": "Libreville",
"quantity": 50,
"service": { "name": "DHL", "recipientName": "Jane Doe" },
"quotation": {
"totalCost": 1840.00,
"unitPrice": 35.00,
"internationalShippingCost": 90.00,
"deliveryCostInChina": 70.00,
"extraFees": 0.00
}
}
]
}
}Modifier une commande
Même structure que la soumission. Repassez l'id de chaque destination pour la mettre à jour sur place (préserve la cotation liée). Les destinations absentes de la requête sont supprimées ; celles sans id sont créées.
Téléverser un fichier
Formulaire multipart. Renvoie une URL S3 permanente que vous pouvez réutiliser comme productImageUrl, url de proof-of-payment, etc.
curl -X POST https://kuaisourcing.com/api-back/api/partner/uploads \
-H "x-api-key: $KEY" \
-F "file=@receipt.pdf" \
-F "purpose=proof-of-payment"
# Response
{
"success": true,
"data": {
"url": "https://files.example.com/uploads/receipt.pdf",
"size": 27695,
"contentType": "application/pdf"
}
}Acceptés : jpg, jpeg, png, webp, pdf, mp4, mov, webm. 25 Mo maximum.
Soumettre une preuve de paiement
Attachez un reçu à une commande existante. Téléversez d'abord le fichier via l'endpoint uploads et passez l'URL renvoyée ici.
{
"country": "Gabon",
"url": "https://files.example.com/uploads/receipt.pdf",
"paymentNote": "Bank transfer EUR to USD, reference KS0000"
}En cas de succès, le statut passe automatiquement de Unpaid à Payment pending et un webhook order.status_changed est émis.
Lister les services disponibles
Dédupliqué par nom (insensible à la casse). Un service peut opérer dans plusieurs pays, chaque ligne montre la liste de couverture.
{
"success": true,
"data": [
{ "id": "00000000-0000-4000-8000-000000000001", "name": "Example Freight Co", "countries": ["Morocco"] },
{ "id": "00000000-0000-4000-8000-000000000002", "name": "Sample Logistics", "countries": ["Senegal", "Madagascar"] },
{ "id": "00000000-0000-4000-8000-000000000003", "name": "Demo Shipping Line", "countries": ["Spain"] }
]
}Règles de sélection de service
| Champ envoyé | Comportement |
|---|---|
| serviceId | Préféré, non ambigu, lie à cette ligne du catalogue |
| service | Correspondance par nom, insensible à la casse. "DHL" = "dhl" = "Dhl". |
| service: "Other ..." | Voir la livraison auto-gérée, champs supplémentaires requis. |
| Toute autre valeur | 400 avec "Service 'X' is not in our catalog…" |
Livraison auto-gérée
Quand vous gérez vous-même la livraison, votre coursier, un transitaire local, ou un retrait personnel, définissez service: "Other ..." sur la destination et fournissez les mêmes champs qu'un utilisateur normal remplit dans notre interface.
| Champ | Requis | Rôle |
|---|---|---|
| customService | oui | Nom libre du transitaire/coursier (ex. "Mon transitaire local de Tunis") |
| recipientName | oui | Personne recevant à destination |
| contactNumber | oui | Téléphone du destinataire, utilisé par le coursier local |
| isCompanyService | optionnel | Défaut false. Mettez true pour les transitaires entreprise déclarés. |
| address, city | optionnel | Hérité de la destination, également utilisé comme adresse de livraison. |
Ces lignes sont marquées userSubmitted=true côté serveur, elles n'apparaissent donc jamais dans le catalogue partagé des services.
Si un champ requis manque, l'API renvoie 400 avec un pointeur vers cette section.
Webhooks
Configurez une URL de webhook lors du provisioning de votre clé API. Nous livrons les événements de manière asynchrone, signés en HMAC-SHA256, avec réessais en cas d'échec.
| Événement | Déclenché quand… |
|---|---|
| quotation.created | Un admin émet une cotation chiffrée sur une de vos destinations |
| quotation.updated | Une cotation existante est modifiée |
| order.status_changed | Le statut change (ex. Unpaid → Paid → In Production → Shipped) |
| realimages.added | Des photos / vidéos du produit réel sont téléversées |
Si un notificationEmail est aussi configuré sur votre clé, les mêmes événements déclenchent un e-mail digest parallèle. Les deux canaux sont optionnels.
Meilleur effort. Nous réessayons sur les réponses non-2xx avec backoff exponentiel (1 s, 2 s, 4 s, 8 s, 16 s). Répondez 2xx dans les 10 secondes ou la tentative est considérée comme échouée.
Format des erreurs
Toutes les erreurs partagent la même enveloppe. Le statut HTTP est porteur de sens, votre client doit l'aiguiller avant de lire le corps.
HTTP 400 Bad Request
{
"success": false,
"data": null,
"error": "destinations: At least one destination is required",
"timestamp": "2026-05-18T11:42:03.581"
}| Code | Signification |
|---|---|
400 | Validation échouée, voir le champ error pour le détail. Ne réessayez pas sans corriger. |
401 | x-api-key manquante ou invalide |
403 | Clé révoquée ou quota dépassé |
404 | Commande ou ressource non trouvée (ou non détenue par votre clé) |
409 | Commande dans un statut non modifiable, modification impossible |
429 | Limite de débit, temporisez et réessayez |
500 | Erreur serveur, réessai sûr avec backoff exponentiel |
Aide-mémoire des endpoints
| Méthode · Chemin | Ce que ça fait |
|---|---|
| POST /api/partner/sourcing | Créer une demande d'approvisionnement |
| GET /api/partner/sourcing | Lister vos commandes (paginées, filtrables) |
| GET /api/partner/sourcing/{orderId} | Récupérer une commande (détail complet) |
| GET /api/partner/sourcing/by-order-id/{customOrderId} | Idem, par code KS |
| PUT /api/partner/sourcing/{orderId} | Modifier (seulement Processing / Unpaid) |
| POST /api/partner/uploads | Téléverser un fichier → URL S3 permanente |
| POST /api/partner/sourcing/{orderId}/proof-of-payment | Attacher un reçu ; le statut passe Unpaid → Payment pending |
| GET /api/partner/services | Lister le catalogue des services de livraison |