Die Entwicklerdokumentation ist auf Englisch verfügbar.
Quickstart
Create your first test delivery: pick a vehicle type, quote a route, book it, and follow the simulated courier.
This guide books a delivery from Köln to Düsseldorf with a test key. Test deliveries are never dispatched or billed. A simulated courier, the Robocourier, moves them through every status.
Before you start#
You need a business or fleet workspace in Maxmove in which you are an owner or admin. Only owners and admins can create API keys.
Create a test delivery#
Create a test key
In the dashboard, open Settings → API keys and select Create API key. Choose Test, keep the permissions you need, and copy the key. It starts with
mm_test_and is shown only once.Store it in an environment variable:
export MAXMOVE_KEY="mm_test_…"See Authentication for permissions and expiration.
Pick a vehicle type
List the vehicle types you can book. Pass an
idfrom the response asvehicle_type_idin the next steps. The examples usecourier.curl https://api.maxmove.com/v1/vehicle-types \ -H "x-api-key: $MAXMOVE_KEY"const BASE_URL = 'https://api.maxmove.com/v1'; const headers = { 'x-api-key': process.env.MAXMOVE_KEY!, 'content-type': 'application/json', }; const res = await fetch(`${BASE_URL}/vehicle-types`, { headers }); const { vehicle_types } = await res.json(); console.log(vehicle_types.map((type: { id: string }) => type.id));import os import requests BASE_URL = "https://api.maxmove.com/v1" headers = {"x-api-key": os.environ["MAXMOVE_KEY"]} res = requests.get(f"{BASE_URL}/vehicle-types", headers=headers) print([vehicle_type["id"] for vehicle_type in res.json()["vehicle_types"]])Price the route
Send pickup and dropoff with their coordinates. Maxmove does not geocode, so send the coordinates your address search returned. The quote is valid for about 5 minutes.
curl -X POST https://api.maxmove.com/v1/quotes \ -H "x-api-key: $MAXMOVE_KEY" -H "content-type: application/json" \ -d '{ "pickup": { "address": "Ehrenstraße 15, 50672 Köln", "latitude": 50.9385, "longitude": 6.9469 }, "dropoff": { "address": "Königsallee 27, 40212 Düsseldorf", "latitude": 51.2233, "longitude": 6.7768 }, "vehicle_type_id": "courier" }'const pickup = { address: 'Ehrenstraße 15, 50672 Köln', latitude: 50.9385, longitude: 6.9469 }; const dropoff = { address: 'Königsallee 27, 40212 Düsseldorf', latitude: 51.2233, longitude: 6.7768 }; const quoteRes = await fetch(`${BASE_URL}/quotes`, { method: 'POST', headers, body: JSON.stringify({ pickup, dropoff, vehicle_type_id: 'courier' }), }); const quote = await quoteRes.json(); console.log(quote.id, quote.amount_cents, quote.currency, quote.valid_until);pickup = {"address": "Ehrenstraße 15, 50672 Köln", "latitude": 50.9385, "longitude": 6.9469} dropoff = {"address": "Königsallee 27, 40212 Düsseldorf", "latitude": 51.2233, "longitude": 6.7768} quote = requests.post( f"{BASE_URL}/quotes", headers=headers, json={"pickup": pickup, "dropoff": dropoff, "vehicle_type_id": "courier"}, ).json() print(quote["id"], quote["amount_cents"], quote["currency"], quote["valid_until"])The response contains the quote
id(qt_…), the price inamount_centsandcurrency, andvalid_until.Book the delivery
Send the same route, the
quote_id, and who the courier meets at each end. TheIdempotency-Keyheader is required: if the request times out, retry it with the same key and body, and you get the same delivery instead of a second one.curl -X POST https://api.maxmove.com/v1/deliveries \ -H "x-api-key: $MAXMOVE_KEY" -H "content-type: application/json" \ -H "Idempotency-Key: order-4711" \ -d '{ "quote_id": "qt_…", "pickup": { "address": "Ehrenstraße 15, 50672 Köln", "latitude": 50.9385, "longitude": 6.9469, "contact": { "name": "Feinkost Ehrenfeld", "phone": "+49 221 1234567" } }, "dropoff": { "address": "Königsallee 27, 40212 Düsseldorf", "latitude": 51.2233, "longitude": 6.7768, "contact": { "name": "Erika Muster", "phone": "+49 170 1234567" }, "instructions": "Ring at reception, 2nd floor." }, "vehicle_type_id": "courier", "external_id": "order-4711" }'const deliveryRes = await fetch(`${BASE_URL}/deliveries`, { method: 'POST', headers: { ...headers, 'Idempotency-Key': 'order-4711' }, body: JSON.stringify({ quote_id: quote.id, pickup: { ...pickup, contact: { name: 'Feinkost Ehrenfeld', phone: '+49 221 1234567' }, }, dropoff: { ...dropoff, contact: { name: 'Erika Muster', phone: '+49 170 1234567' }, instructions: 'Ring at reception, 2nd floor.', }, vehicle_type_id: 'courier', external_id: 'order-4711', }), }); const delivery = await deliveryRes.json(); console.log(deliveryRes.status, delivery.id, delivery.status);delivery = requests.post( f"{BASE_URL}/deliveries", headers={**headers, "Idempotency-Key": "order-4711"}, json={ "quote_id": quote["id"], "pickup": { **pickup, "contact": {"name": "Feinkost Ehrenfeld", "phone": "+49 221 1234567"}, }, "dropoff": { **dropoff, "contact": {"name": "Erika Muster", "phone": "+49 170 1234567"}, "instructions": "Ring at reception, 2nd floor.", }, "vehicle_type_id": "courier", "external_id": "order-4711", }, ).json() print(delivery["id"], delivery["status"])A new delivery answers
201with statuspending. If the route differs from the quoted route, the request fails with400 quote_mismatch; if the quote has expired, with400 quote_expired. Request a new quote and retry.Follow the delivery
Read the tracking snapshot. The Robocourier advances the delivery one status about every 20 seconds until it is
delivered.curl https://api.maxmove.com/v1/deliveries/del_…/tracking \ -H "x-api-key: $MAXMOVE_KEY"const trackingRes = await fetch(`${BASE_URL}/deliveries/${delivery.id}/tracking`, { headers }); const tracking = await trackingRes.json(); console.log(tracking.status, tracking.eta_seconds, tracking.tracking_url);tracking = requests.get( f"{BASE_URL}/deliveries/{delivery['id']}/tracking", headers=headers ).json() print(tracking["status"], tracking["eta_seconds"], tracking["tracking_url"])Instead of polling, register a webhook endpoint to get an event for every change.
Go live#
When your integration works in test mode, create a live key (mm_live_…) and swap it in. The base URL and requests stay the same. Live deliveries are dispatched to real couriers and billed to your workspace on its monthly invoice, so your workspace must be approved for invoice billing first. See Billing.
Webhook endpoints belong to one mode: register your endpoints again with the live key.
Next steps#
Hat das Ihre Frage beantwortet?