Skip to content

Mono-transporteur (cas nominal)

C'est le scénario le plus simple, et le plus courant : un seul transporteur, du chargement à la livraison, sans relais ni sous-traitance. Un TMS externe crée le document ; sur le terrain, trois signatures s'enchaînent — l'expéditeur signe la collecte, le chauffeur signe lui-même l'acceptation de cette collecte (sa propre signature de transporteur, case 23 du CMR papier), puis le destinataire signe la livraison — et le TMS est notifié en temps réel de chaque changement de statut via webhook — il n'a jamais besoin d'interroger l'API en polling.

Points clés à retenir :

  • La souscription au webhook se fait une seule fois, en amont, indépendamment de chaque transport.
  • Le chauffeur peut précharger le document (mode offline) avant même l'arrivée sur site.
  • Chaque signature de collecte ou de livraison déclenche à la fois une transition de statut et une notification webhook — les deux sont synchrones du point de vue du chauffeur, asynchrones du point de vue du TMS. La signature du chauffeur (COLLECTION_ACCEPTANCE) n'a en revanche aucun effet sur le statut ni sur les webhooks : elle s'enchaîne automatiquement juste après la collecte, sur le même appareil.
  • La livraison est bloquée tant que le chauffeur n'a pas signé sa propre acceptation de collecte (signature.collection_acceptance_required, 409, si elle est tentée avant) — voir Signature électronique. Dans ce scénario nominal, l'application chauffeur enchaîne les deux automatiquement et vous n'avez rien à orchestrer pour cela.
  • La consultation du PDF signé se fait à la demande, a posteriori — ce n'est jamais l'API qui pousse le PDF.
sequenceDiagram
    participant TMS as TMS externe
    participant API as API e-CMR
    participant Chauffeur as App chauffeur

    Note over TMS,API: Onboarding préalable (une fois)
    TMS->>API: Souscription webhook (callback URL)
    API-->>TMS: 201 Subscription créée

    Note over TMS,API: Création du transport
    TMS->>API: POST /freightdocuments (externalIdentifier, parties, marchandises)
    API-->>TMS: 201 Created, status=DRAFT

    TMS->>API: POST /freightdocuments/id/issue
    API-->>TMS: 200 OK, status=ISSUED
    API-)TMS: Webhook STATUS=ISSUED

    Note over API,Chauffeur: Préchargement terrain
    API-)Chauffeur: Notification push (mission assignée)
    Chauffeur->>API: GET /freightdocuments/id (mode offline)
    API-->>Chauffeur: Document complet + config signature

    Note over Chauffeur,API: Collecte
    Chauffeur->>API: POST events (arrivée, chargement)
    Chauffeur->>API: POST signature collecte (expéditeur)
    API-->>Chauffeur: 200 OK, status=TRANSIT
    API-)TMS: Webhook STATUS=TRANSIT
    Chauffeur->>API: POST signature collecte-chauffeur (COLLECTION_ACCEPTANCE)
    API-->>Chauffeur: 200 OK, signature enregistrée (statut inchangé)

    Note over Chauffeur,API: Livraison
    Chauffeur->>API: POST events (arrivée, déchargement)
    Chauffeur->>API: POST signature livraison
    API-->>Chauffeur: 200 OK, status=DELIVERED
    API-)TMS: Webhook STATUS=DELIVERED

    Note over TMS,API: Consultation a posteriori
    TMS->>API: GET /freightdocuments/id/pdf
    API-->>TMS: PDF e-CMR signé

Assigner le chauffeur par son numéro de téléphone

Votre TMS sait déjà quel chauffeur roule : c'est lui qui l'a planifié. À la création du document, le rôle CARRIER accepte un champ optionnel driver_phone_number — le numéro tel que vous le stockez dans votre propre fiche chauffeur. Nous résolvons (ou créons) le sous-compte chauffeur correspondant et l'attachons immédiatement au rôle : le document revient déjà assigné, sans qu'un opérateur ait à intervenir dans le portail et sans que vous ayez à connaître d'identifiant de sous-compte chez nous.

driver_phone_number n'est jamais obligatoire. Omis, le document se crée exactement comme avant : tous les sous-comptes du compte titulaire du rôle y ont accès, et l'assignation peut se faire plus tard depuis le portail ou via PATCH /v1/freightdocuments/{id}/roles/{role_id}/assign-subaccount.

Le cycle complet, en un appel

Une commande planifiée chez vous (référence de commande, lieux, marchandise, plaque du tracteur, chauffeur assigné) devient un e-CMR déjà ciblé sur ce chauffeur :

{
  "external_identifier": "CMD-2026-4711",
  "transport_reference": "TR-4711",
  "goods_lines": [
    {
      "package_count": 20,
      "packaging_method": "Palettes",
      "nature_of_goods": "Grain de café",
      "gross_weight_kg": 2000
    }
  ],
  "roles": [
    {
      "role_type": "CARRIER",
      "account_id": "<votre propre account_id>",
      "party_snapshot": { "name": "Lotrans SA" },
      "vehicle_plate": "VD-123456",
      "driver_phone_number": "+41787083851",
      "driver_name": "Jane Driver"
    },
    {
      "role_type": "PLACEOFTAKINGOVER",
      "email": "quai@expediteur.example",
      "party_snapshot": {
        "name": "Expéditeur SA",
        "address": { "street": "Rue 1", "postal_code": "1000", "city": "Lausanne", "country": "CH" }
      }
    },
    {
      "role_type": "PLACEOFDELIVERY",
      "email": "reception@destinataire.example",
      "party_snapshot": { "name": "Destinataire SA" }
    }
  ]
}

La réponse 201 renvoie le rôle CARRIER avec son assigned_subaccount_id renseigné — c'est le sous-compte du chauffeur, résolu ou créé par cet appel :

{
  "id": "...",
  "status": "DRAFT",
  "roles": [
    {
      "role_type": "CARRIER",
      "vehicle_plate": "VD-123456",
      "assigned_subaccount_id": "8141560d-8878-43c6-888b-db25383ef0ef"
    }
  ]
}

Enchaînez ensuite normalement avec POST /freightdocuments/{id}/issue : à partir de là, le flux est celui du schéma ci-dessus, à ceci près que la mission n'est visible que par ce chauffeur-là, et non par tous les sous-comptes de votre compte.

Ce qu'il faut savoir avant de brancher ce champ

Envoyez toujours l'indicatif pays. Les formes nationales sont acceptées, mais interprétées dans la région par défaut de la plateforme (CH en standard) : 0787083851, 0041787083851 et +41787083851 désignent bien le même mobile suisse, en revanche un numéro national espagnol comme 612345678 sera compris comme le suisse +41612345678 — un numéro valide, mais pas le bon, et aucune erreur ne sera renvoyée. En E.164 (+34612345678), il n'y a aucune ambiguïté possible.

Un numéro non résolvable est rejeté explicitement, avec freight_document.invalid_driver_phone_number (400) : rien n'est créé, aucun SMS n'est envoyé, et votre external_identifier reste libre — vous pouvez corriger le numéro et rejouer le même appel à l'identique.

Le chauffeur reçoit une invitation SMS, une seule fois. Un numéro que nous n'avons jamais vu sous votre compte déclenche l'envoi d'un lien d'inscription au chauffeur (il choisit lui-même son mot de passe ; recevoir et ouvrir ce lien est ce qui prouve le numéro). Un numéro déjà connu — d'un transport précédent, d'une fiche créée par un opérateur, ou d'une signature passée — est simplement réutilisé, sans nouveau SMS. Cet envoi est soumis à une limite de débit par compte : un flux d'ordres portant chacun un nouveau numéro finira par recevoir un 429, comme sur l'endpoint d'invitation du portail. Les ordres portant un chauffeur déjà connu ne consomment jamais ce quota.

Uniquement sur votre propre rôle CARRIER. Le champ n'est valide que sur un rôle CARRIER dont l'account_id est le vôtre — un sous-traitant assigne ses propres chauffeurs, depuis son propre compte. Il n'est accepté qu'à la création du document : sur l'ajout de rôle post-création (POST /freightdocuments/{id}/roles), il est refusé explicitement plutôt qu'ignoré silencieusement.

Un changement de numéro crée un nouveau chauffeur. Un chauffeur qui change de numéro donne un nouveau sous-compte, distinct de l'ancien : il n'y a aucun rapprochement automatique entre les deux. Ses signatures passées restent attachées au sous-compte qui les a réellement produites — c'est ce lien qui fait leur valeur de preuve.

N'essayez pas de créer le sous-compte vous-même en amont. POST /v1/accounts/me/subaccounts (et son équivalent /invite) n'accepte que la session d'un utilisateur connecté au portail : avec une clé API il renvoie 401, avec un jeton OAuth2 client_credentials un 403 auth.insufficient_scope. driver_phone_number est aujourd'hui la seule voie d'accès machine à la gestion d'un chauffeur.