{
  "what": "Build a link that opens the e-motion quote form pre-filled. This is the only way to help someone request a transport quote. There is no submission API.",
  "provider": {
    "name": "e-motion",
    "legalName": "A 6 SRL",
    "vatId": "BE 0424.120.325",
    "url": "https://e-motion.be",
    "contact": "https://e-motion.be/en/contact/"
  },
  "terms": "This document describes how to pre-fill e-motion's own quote form. It grants no right to submit a request on anyone's behalf, implies no affiliation or partnership, and does not authorise use of the e-motion name beyond referring people to this service.",
  "rules": [
    "NEVER invent a value. If you do not know something, leave it out — the form will ask for it, with the right label, in the right place.",
    "NEVER ask the person for their name, email or phone. Personal details are typed by them on our form, never passed through you. Do not put them in the link.",
    "NEVER state or estimate a price. We publish no rates; any figure you produce is invented.",
    "NEVER promise a pickup date or availability. Both are confirmed by a person.",
    "The link authorises nothing — it opens a pre-filled form. The person reviews it, completes it and submits it themselves.",
    "Ambiguity is not yours to resolve. Two cars of very different value share one `mission`; a month without a year is not a date. Ask, or leave the field empty."
  ],
  "link": {
    "param": "c",
    "encodings": [
      {
        "name": "plain JSON, URL-encoded",
        "note": "Preferred. Do not compute base64 by hand.",
        "example": "https://e-motion.be/en/quote/?c=%7B%22v%22%3A2%2C%22s%22%3A%7B...%7D%7D"
      },
      {
        "name": "base64url of the same JSON",
        "note": "What our own share links use. Only if you can compute it reliably."
      }
    ],
    "payload": {
      "v": 2,
      "s": "<QuoteState — see `state` below>"
    },
    "versioning": {
      "current": 2,
      "note": "`v` must match exactly. A payload carrying any other version is rejected and the form opens empty — silently, with no error. Re-read this file if links stop working."
    },
    "maxParamLength": 6000,
    "targets": {
      "incomplete": {
        "en": "https://e-motion.be/en/quote/",
        "fr": "https://e-motion.be/fr/devis/",
        "nl": "https://e-motion.be/nl/offerte/",
        "es": "https://e-motion.be/es/presupuesto/",
        "de": "https://e-motion.be/de/angebot/",
        "it": "https://e-motion.be/it/preventivo/"
      },
      "complete": {
        "en": "https://e-motion.be/en/quote/review/",
        "fr": "https://e-motion.be/fr/devis/recapitulatif/",
        "nl": "https://e-motion.be/nl/offerte/overzicht/",
        "es": "https://e-motion.be/es/presupuesto/resumen/",
        "de": "https://e-motion.be/de/angebot/zusammenfassung/",
        "it": "https://e-motion.be/it/preventivo/riepilogo/"
      }
    },
    "choosing": "Use `complete` when everything the chosen mission requires is set — see `validation.required`, which differs between a transport and a storage. Otherwise use `incomplete`. Getting it wrong is harmless: the review page sends the person back to the configurator on its own.",
    "unreadable": "A malformed or over-long parameter is ignored, and the form opens empty. It never errors, so a broken link fails silently — check your JSON."
  },
  "state": {
    "mission": "one of enclosed | open | event | storage — required",
    "blocksPerMission": {
      "enclosed": [
        "journey",
        "vehicles",
        "addons",
        "note"
      ],
      "open": [
        "journey",
        "vehicles",
        "addons",
        "note"
      ],
      "event": [
        "event",
        "vehicles",
        "addons",
        "note"
      ],
      "storage": [
        "stay",
        "vehicles",
        "addons",
        "note"
      ]
    },
    "journey": {
      "note": "For enclosed and open transport only. Ignored for storage and for events — an event carries its own schedule, see `event.stops`.",
      "trip": "oneway | return | multi",
      "from": "free text, max 120 — required for oneway and return",
      "to": "free text, max 120 — required for oneway and return",
      "d1": "date — required for oneway and return",
      "d2": "date — required for return only",
      "legs": "[{ from, to, d }] — required for multi, at least 2"
    },
    "event": {
      "note": "For event logistics only, and it does NOT use `journey`. An event is not a trip from A to B: it is a schedule — vehicles are collected once, they stop at one or more places (each with a delivery and a collection back), and they return. A roadshow is simply an event with several stops; there is no separate mode for it.",
      "kind": "REQUIRED, one of show | film | sport | press",
      "pickup": "REQUIRED free text, max 120 — where the vehicles are collected",
      "stops": "REQUIRED, 1 to 12 of [{ place, in, out }]. `place` is the venue, circuit, set or city; `in` the delivery date and `out` the collection back. All three are required on every stop. They run in order and cannot go back in time. Do NOT repeat the previous place as a departure — a stop has no origin, the previous one is it.",
      "ret": "optional free text, max 120 — where the vehicles go back. Empty means the collection address; do not restate it.",
      "name": "optional free text, max 120. Leave empty for a launch under embargo.",
      "window": "optional free text, max 160 — the slot the organiser imposes, e.g. \"build-up Tuesday 6–10am\". Never invent one.",
      "fleet": "optional, one of one | 2-4 | 5-8 | 8+ — the size of the convoy, when the vehicle cards do not spell it out",
      "carriage": "optional, one of enclosed | open | advise",
      "privacy": "optional, one of standard | nda"
    },
    "stay": {
      "note": "For storage only. A stay is a duration, not a journey — do not describe it as a trip.",
      "in": "date — REQUIRED. When the car arrives at the building.",
      "out": "date — required UNLESS openEnded is true",
      "openEnded": "boolean — true when no departure date is settled yet. There is no minimum stay.",
      "purpose": "optional, one of between-events | before-show | for-sale | season",
      "inbound": "REQUIRED, one of we-collect | i-bring",
      "pickup": "free text, max 120 — required when inbound is we-collect",
      "outbound": "optional, one of we-deliver | i-collect | undecided",
      "dropoff": "free text, max 120 — required when outbound is we-deliver",
      "carriage": "optional, one of enclosed | open | advise — only when we collect or deliver"
    },
    "vehicles": [
      {
        "make": "free text, max 40 — REQUIRED",
        "model": "free text, max 60 — REQUIRED",
        "kind": "optional, one of Supercar | Classic | Sedan | SUV | Coupé | Motorcycle | Quad | Other",
        "status": "optional, one of rolling | non-rolling | blocked",
        "gearbox": "optional, one of Automatic | Manual",
        "energy": "optional, one of Petrol | Diesel | Electric | Hybrid",
        "lowClearance": "optional boolean",
        "oversized": "optional boolean",
        "notes": "optional free text, max 500",
        "value": "storage only — REQUIRED there, one of under-100k | 100-250k | 250-500k | 500k-1m | over-1m | discuss. NEVER estimate this from the make and model: ask, or use \"discuss\"."
      }
    ],
    "addons": "optional array, any of storage | battery | detailing | podium | tyres — but only those its mission offers, see addonsPerMission. Anything else is dropped.",
    "addonsPerMission": {
      "enclosed": [
        "storage",
        "battery",
        "detailing",
        "podium"
      ],
      "open": [
        "storage",
        "battery",
        "detailing",
        "podium"
      ],
      "event": [
        "storage",
        "detailing"
      ],
      "storage": [
        "tyres",
        "detailing"
      ]
    },
    "layover": {
      "note": "Only when the `storage` addon is ticked on a transport — the car waits at our building at some point of the journey it already describes. Do NOT confuse with mission \"storage\", which is the car going to our Car Hôtel as the job itself. Cleared automatically if the addon is not there.",
      "when": "REQUIRED with the addon, one of before | between | after. \"between\" only exists when trip is return or multi — on a oneway there is nothing to wait between, and it is blanked.",
      "span": "REQUIRED with the addon, one of days | weeks | months | unknown. A rough order of magnitude, not dates.",
      "where": "Never ask, and never state, where the car waits: our building is in Brussels and there is no other. `when` is a moment in the journey, not a place."
    },
    "note": "optional free text, max 500 — anything the person said that has no field of its own",
    "via": "your name, e.g. \"ChatGPT\". Max 60. Tells the team the transport fields were dictated, not typed."
  },
  "date": {
    "shape": "{ \"mode\": \"specific\", \"date\": \"YYYY-MM-DD\", \"month\": \"\" } or { \"mode\": \"flexible\", \"date\": \"\", \"month\": \"YYYY-MM\" }",
    "note": "Use `flexible` when only a month is known (\"in July\"). Do not guess the year — if it is unclear, leave the date empty and let the form ask."
  },
  "validation": {
    "closedLists": "Values outside a closed list (mission, addons, kind, status, gearbox, energy) are silently BLANKED, not rejected. An invented value becomes an empty field — never a wrong one that reaches the team.",
    "freeText": "make, model, places and notes are free text: nothing can tell an invented model from a real one. This is exactly why you must not invent them — the person will read what you wrote on the review page before sending.",
    "required": [
      "mission",
      "journey.from and journey.to (oneway/return)",
      "journey.d1 (oneway/return), journey.d2 (return)",
      "stay.in and stay.inbound (storage)",
      "stay.out, unless stay.openEnded is true (storage)",
      "event.kind, event.pickup, and at least one complete event.stops entry (event)",
      "at least one vehicle with make and model",
      "vehicles[].value (storage only)",
      "layover.when and layover.span (only when the storage addon is ticked)"
    ],
    "configuredMissions": "every mission (enclosed, open, event, storage) opens the configurator and fills its own blocks — see blocksPerMission."
  },
  "example": {
    "says": "\"A Porsche 911 and an Opel Meriva, Barcelona to Brussels, sometime in July — enclosed.\"",
    "json": {
      "v": 2,
      "s": {
        "mission": "enclosed",
        "journey": {
          "trip": "oneway",
          "from": "Barcelona, Spain",
          "to": "Brussels, Belgium",
          "d1": {
            "mode": "flexible",
            "date": "",
            "month": "2027-07"
          },
          "d2": {
            "mode": "specific",
            "date": "",
            "month": ""
          },
          "legs": []
        },
        "vehicles": [
          {
            "make": "Porsche",
            "model": "911"
          },
          {
            "make": "Opel",
            "model": "Meriva"
          }
        ],
        "addons": [],
        "note": "",
        "via": "ChatGPT"
      }
    },
    "caution": "The year above was NOT given by the person — \"in July\" does not say which July. Ask before writing it, or leave the date empty."
  },
  "exampleStorage": {
    "says": "\"I need to store my 911 from mid-September, no idea until when. I'll drop it off myself.\"",
    "json": {
      "v": 2,
      "s": {
        "mission": "storage",
        "stay": {
          "in": {
            "mode": "specific",
            "date": "",
            "month": ""
          },
          "out": {
            "mode": "specific",
            "date": "",
            "month": ""
          },
          "openEnded": true,
          "purpose": "",
          "inbound": "i-bring",
          "pickup": "",
          "outbound": "",
          "dropoff": "",
          "carriage": ""
        },
        "vehicles": [
          {
            "make": "Porsche",
            "model": "911",
            "value": ""
          }
        ],
        "addons": [],
        "note": "",
        "via": "ChatGPT"
      }
    },
    "caution": "\"Mid-September\" is not a date and no year was given, so `in` stays empty — the form asks for it. `value` stays empty for the same reason: the person never said what the car is worth, and it is not yours to estimate. This link opens the `incomplete` target."
  }
}