Aller au contenu
DROPP

Développeurs

Connectez votre boutique en ligne à DROPP

Proposez la livraison en point relais à votre page de commande, créez les colis automatiquement et suivez-les en temps réel. Une API REST simple, en JSON.

Démarrage rapide

1. Un compte marchand

Créez votre compte marchand dans l'app DROPP (ou demandez-le à notre équipe).

2. Une clé de test

Dans l'app : Profil → Intégration e-commerce → Nouvelle clé, option « Clé de test ».

3. Vos premiers colis

Affichez les relais et le prix au panier, créez les colis à la commande, faites-les avancer avec le simulateur.

4. En réel

Créez une clé réelle, enregistrez votre URL de webhook en HTTPS, et c'est parti.

Adresse de l'API : https://api.dropp237.com/api/v1

Comment ça marche

  1. 1Au panier, votre site affiche les points relais DROPP et le prix de la livraison, calculé d'après le poids de la commande.
  2. 2L'acheteur choisit son relais et paie votre boutique : en ligne, ou au retrait (contre-remboursement).
  3. 3Votre site crée le colis par l'API. Il apparaît « à payer » dans votre app DROPP.
  4. 4Vous payez la livraison à DROPP dans l'app, ou au relais en déposant le colis. Rien ne part sans être payé.
  5. 5DROPP transporte le colis. L'acheteur reçoit un code par SMS et le retire au relais choisi.
  6. 6Paiement au retrait : l'acheteur paie au relais et vous recevez la totalité par Mobile Money, sans aucune retenue.
SituationCe qui se passe
Colis non payé ni déposé sous 7 joursSupprimé automatiquement (webhook shipment.deleted).
Colis payé mais jamais déposé sous 14 joursAnnulé, et les frais vous sont remboursés.
Colis non retiré par l'acheteurIl revient au relais de départ. Vous le récupérez avec votre code retours (dans votre profil) en payant 50 % du prix aller.

Authentification

Chaque appel porte votre clé secrète dans l'en-tête Authorization. Appelez l'API depuis votre serveur uniquement : la clé ne doit jamais apparaître dans le navigateur ni dans une app mobile.

Authorization: Bearer dropp_sk_live_xxxxxxxxxxxxxxxx
CléUsage
dropp_sk_test_…Mode test : vrais relais et vrais prix, colis fictifs (TST-…), aucun paiement.
dropp_sk_live_…Mode réel : vrais colis (DRP-…).

Les clés se créent et se révoquent dans l'app marchand, avec un code SMS. Le secret n'est affiché qu'une fois : gardez-le dans une variable d'environnement. Pour éviter un doublon si vous réessayez une requête, ajoutez l'en-tête Idempotency-Key : la même requête renvoyée avec la même clé reçoit la première réponse.

Points relais

GET/ecommerce/relay-points?city=Douala

Les relais ouverts, à proposer à l'acheteur. Gardez l'id du relais choisi : il sert à créer le colis.

curl "https://api.dropp237.com/api/v1/ecommerce/relay-points?city=Douala" \
  -H "Authorization: Bearer $DROPP_API_KEY"
Réponse
[
  {
    "id": "8f0c2c1e-5b7a-4a52-9d1e-2b8f3c4d5e6f",
    "name": "DROPP Akwa",
    "city": "Douala",
    "neighborhood": "Akwa",
    "address": "Papeterie du Centre, boulevard de la Liberté",
    "latitude": 4.0511,
    "longitude": 9.7043,
    "phone_number": "+237690000000",
    "photo_url": null
  }
]

Prix et catégories

GET/ecommerce/quote?weight=1.5

Envoyez le poids total de la commande en kg : DROPP choisit la catégorie. Pour un objet léger mais encombrant, imposez-la avec package_size=M ou L. Le prix est toujours celui entre deux villes.

CatégoriePoids maximumPrix
S1 kg2 000 FCFA
M5 kg2 750 FCFA
L15 kg3 500 FCFA
curl "https://api.dropp237.com/api/v1/ecommerce/quote?weight=1.5" \
  -H "Authorization: Bearer $DROPP_API_KEY"

# {"package_size": "M", "weight": 1.5, "shipping_fee": 2750.0, "currency": "XAF"}
Le relais pèse le colis au dépôt : s'il est plus lourd que sa catégorie, vous payez la différence sur place.

Créer un colis

POST/ecommerce/shipments

À appeler quand la commande est validée. Le colis est créé « à payer » : vous le payez dans l'app DROPP ou au relais en le déposant.

ChampDescription
external_referenceVotre n° de commande. Un seul colis par commande : un deuxième appel renvoie 409.
recipient.nameNom de l'acheteur.
recipient.phone_numberNuméro camerounais : il reçoit le code de retrait par SMS.
destination_relay_idRelais choisi par l'acheteur.
weightPoids total en kg (ou package_size : S, M, L).
cod_amountMontant que l'acheteur paie au relais (0 si payé en ligne). Il vous est reversé en entier.
content_descriptionFacultatif : le contenu du colis.
curl -X POST "https://api.dropp237.com/api/v1/ecommerce/shipments" \
  -H "Authorization: Bearer $DROPP_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-CMD-1001" \
  -d '{
    "external_reference": "CMD-1001",
    "recipient": { "name": "Paul Mbarga", "phone_number": "677112233" },
    "destination_relay_id": "8f0c2c1e-5b7a-4a52-9d1e-2b8f3c4d5e6f",
    "weight": 1.5,
    "cod_amount": 0,
    "content_description": "Baskets"
  }'
Réponse
{
  "tracking_id": "DRP-3F6D45992EFD",
  "external_reference": "CMD-1001",
  "status": "CREATED",
  "package_size": "M",
  "weight": 1.5,
  "shipping_fee": 2750.0,
  "currency": "XAF",
  "fee_paid": false,
  "cod_amount": 0.0,
  "cod_status": "NONE",
  "recipient_name": "Paul Mbarga",
  "recipient_phone": "+237677112233",
  "destination_relay": { "name": "DROPP Akwa", "city": "Douala", "...": "..." },
  "expires_in_seconds": 604800,
  "timeline": [{ "status": "CREATED", "relay_point_name": null, "created_at": "…" }],
  "test_mode": false
}

Suivre et annuler

GET/ecommerce/shipments/{tracking_id}

GET/ecommerce/shipments?external_reference=CMD-1001

DELETE/ecommerce/shipments/{tracking_id}

Le détail donne le statut, l'historique, le relais, le contre-remboursement et son versement. L'annulation n'est possible que tant que la livraison n'est pas payée ; ensuite, contactez le support.

# One parcel
curl "https://api.dropp237.com/api/v1/ecommerce/shipments/DRP-3F6D45992EFD" -H "Authorization: Bearer $DROPP_API_KEY"

# By order number
curl "https://api.dropp237.com/api/v1/ecommerce/shipments?external_reference=CMD-1001" -H "Authorization: Bearer $DROPP_API_KEY"

# Cancel (only while the fee is not paid)
curl -X DELETE "https://api.dropp237.com/api/v1/ecommerce/shipments/DRP-3F6D45992EFD" -H "Authorization: Bearer $DROPP_API_KEY"

Statuts

StatutSignification
CREATEDCréé, livraison à payer
PAIDLivraison payée, à déposer au relais
DROPPED_AT_ORIGINDéposé au relais de départ
PICKED_UP / IN_CONSOLIDATION_BAG / IN_TRANSITEn route
DROPPED_AT_DESTINATIONArrivé au relais, en cours de réception
READY_FOR_PICKUPPrêt : l'acheteur a reçu son code
DELIVEREDRemis à l'acheteur
RETURNED / RETURN_IN_TRANSITNon retiré : retour vers le relais de départ
RETURN_AT_ORIGINRevenu au relais de départ, à récupérer
RETURNED_TO_SENDERRendu à la boutique
CANCELLED / LOST / DAMAGEDAnnulé, perdu ou endommagé : le support vous contacte

Webhooks

DROPP appelle votre URL à chaque événement : plus besoin d'interroger l'API. Enregistrez une URL HTTPS publique ; la réponse contient le secret de signature, affiché une seule fois.

curl -X PUT "https://api.dropp237.com/api/v1/ecommerce/webhook" \
  -H "Authorization: Bearer $DROPP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://ma-boutique.cm/webhooks/dropp"}'

# {"url": "...", "test_mode": false, "secret": "whsec_..."}  <- keep the secret

# Send a test event
curl -X POST "https://api.dropp237.com/api/v1/ecommerce/webhook/test" -H "Authorization: Bearer $DROPP_API_KEY"
ÉvénementQuand
shipment.status_changedChaque changement de statut (data.previous_status)
shipment.payment_failedLe paiement de la livraison a échoué
shipment.cod_paidL'acheteur a payé au relais
shipment.deletedColis non payé supprimé (data.reason : expired ou cancelled)
pingTest demandé par vous
Ce que reçoit votre serveur
POST /webhooks/dropp
Dropp-Signature: t=1760781120,v1=5f2c…
Dropp-Event: shipment.status_changed
Dropp-Event-Id: evt_3f1c…

{
  "id": "evt_3f1c…",
  "type": "shipment.status_changed",
  "created_at": "2026-10-18T09:12:00+00:00",
  "test_mode": false,
  "data": {
    "previous_status": "IN_TRANSIT",
    "shipment": { "tracking_id": "DRP-3F6D45992EFD", "external_reference": "CMD-1001", "status": "READY_FOR_PICKUP", "...": "..." }
  }
}

Vérifiez toujours la signature avant de croire un appel : HMAC-SHA256 du texte « t.corps brut » avec votre secret, comparé à v1, et t de moins de 5 minutes.

import crypto from "node:crypto";
import express from "express";

const app = express();
// The signature is computed on the raw body: do not parse it before.
app.post("/webhooks/dropp", express.raw({ type: "application/json" }), (req, res) => {
  const header = req.get("Dropp-Signature") ?? "";
  const { t, v1 } = Object.fromEntries(header.split(",").map((p) => p.split("=")));
  const expected = crypto
    .createHmac("sha256", process.env.DROPP_WEBHOOK_SECRET)
    .update(`${t}.${req.body}`)
    .digest("hex");
  const fresh = Math.abs(Date.now() / 1000 - Number(t)) < 300;
  if (!v1 || !fresh || !crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(expected))) {
    return res.sendStatus(401);
  }
  const event = JSON.parse(req.body);
  // Ignore an event.id already handled, then update the order.
  res.sendStatus(200);
});
Répondez 2xx rapidement. Sinon DROPP réessaie pendant environ 2 jours (1 min, 5 min, 15 min, 1 h, 3 h, 6 h, 12 h, 24 h). Un même événement peut arriver deux fois : ignorez un id déjà traité. Les derniers envois sont visibles avec GET /ecommerce/webhook/deliveries.

Mode test

Avec une clé de test, tout fonctionne comme en réel (relais, prix, webhooks), mais les colis sont fictifs : aucun relais ne les voit, aucun paiement n'est demandé. Faites-les avancer vous-même :

POST/ecommerce/test/shipments/{tracking_id}/simulate

actionEffet
advanceÉtape suivante : payé, déposé, en route, prêt au retrait, livré (le paiement au retrait passe alors à payé)
expireLe colis non payé expire et est supprimé
# Test key: dropp_sk_test_...
curl -X POST "https://api.dropp237.com/api/v1/ecommerce/test/shipments/TST-7BABF5615428/simulate" \
  -H "Authorization: Bearer $DROPP_TEST_KEY" \
  -H "Content-Type: application/json" \
  -d '{"action": "advance"}'

Erreurs

Une erreur renvoie un code HTTP et une phrase claire, à afficher telle quelle : {"detail": "…"}

CodeSignification
400Donnée refusée (relais fermé, numéro invalide, colis trop lourd…)
401Clé absente, inconnue ou révoquée
403Compte marchand bloqué, ou action réservée aux clés de test
404Colis introuvable (ou d'un autre marchand)
409Commande déjà envoyée, ou paiement en cours
422Champ manquant ou mal formé

Mise en production

  • ✓La clé réelle est dans une variable d'environnement de votre serveur, jamais dans le code ni le navigateur.
  • ✓Chaque création de colis envoie external_reference et Idempotency-Key.
  • ✓Le webhook est en HTTPS, vérifie la signature et ignore les événements déjà traités.
  • ✓Le prix affiché au panier vient de /ecommerce/quote.
  • ✓Les erreurs de l'API sont affichées au marchand, pas avalées.

Une question sur l'intégration ?

Notre équipe vous aide à connecter votre boutique, quelle que soit sa plateforme.