Skip to content
Last updated

Quickstart

Make your first MVMNT API call in about 5 minutes: get a token, create a customer, create two locations, then create an order.

Prerequisites

  • MVMNT API credentials: client_id and client_secret (see Authentication)
  • A shell with curl
  • For code samples:
    • JavaScript: Node 18+
    • Python: Python 3.9+ and pip install requests

Base URLs

  • Token: https://api.mvmnt.io/oauth2/token
  • API: https://api.mvmnt.io/v1

Step 1: Set environment variables

export MVMNT_CLIENT_ID="YOUR_CLIENT_ID"
export MVMNT_CLIENT_SECRET="YOUR_CLIENT_SECRET"

Step 2: Request an access token

cURL

curl -sS -X POST "https://api.mvmnt.io/oauth2/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "client_id=${MVMNT_CLIENT_ID}" \
  -d "client_secret=${MVMNT_CLIENT_SECRET}"

Expected output (HTTP 200 OK):

{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "Bearer",
  "expires_in": 3600
}

Copy the access_token into an environment variable:

export MVMNT_TOKEN="PASTE_ACCESS_TOKEN_HERE"

JavaScript (Node 18+)

// quickstart-token.mjs
const tokenRes = await fetch("https://api.mvmnt.io/oauth2/token", {
  method: "POST",
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
  body: new URLSearchParams({
    grant_type: "client_credentials",
    client_id: process.env.MVMNT_CLIENT_ID,
    client_secret: process.env.MVMNT_CLIENT_SECRET,
  }),
});

if (!tokenRes.ok) {
  console.error(await tokenRes.text());
  process.exit(1);
}

const { access_token, token_type, expires_in } = await tokenRes.json();
console.log({ token_type, expires_in, access_token: access_token.slice(0, 24) + "..." });

Run:

node quickstart-token.mjs

Python

# quickstart_token.py
import os
import requests

res = requests.post(
    "https://api.mvmnt.io/oauth2/token",
    headers={"Content-Type": "application/x-www-form-urlencoded"},
    data={
        "grant_type": "client_credentials",
        "client_id": os.environ["MVMNT_CLIENT_ID"],
        "client_secret": os.environ["MVMNT_CLIENT_SECRET"],
    },
    timeout=30,
)

res.raise_for_status()
data = res.json()
print({"token_type": data["token_type"], "expires_in": data["expires_in"], "access_token_prefix": data["access_token"][:24] + "..."})

Run:

python quickstart_token.py

Step 3: Create a customer

This creates a shipper profile you can attach locations and orders to.

cURL

curl -sS -X POST "https://api.mvmnt.io/v1/customers" \
  -H "Authorization: Bearer ${MVMNT_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Acme Industrial Plastics",
    "status": "ACTIVE",
    "website": "https://acme-industrial-plastics.example",
    "phoneNumber": "+1-214-555-0199"
  }'

Expected output (HTTP 201 Created):

{
  "object": "CUSTOMER",
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "name": "Acme Industrial Plastics",
  "status": "ACTIVE",
  "createdAt": "2026-01-22T18:30:00Z",
  "updatedAt": "2026-01-22T18:30:00Z",
  "deletedAt": null
}

Save the id as CUSTOMER_ID for the next step.

JavaScript

// quickstart-customer.mjs
async function getToken() {
  const res = await fetch("https://api.mvmnt.io/oauth2/token", {
    method: "POST",
    headers: { "Content-Type": "application/x-www-form-urlencoded" },
    body: new URLSearchParams({
      grant_type: "client_credentials",
      client_id: process.env.MVMNT_CLIENT_ID,
      client_secret: process.env.MVMNT_CLIENT_SECRET,
    }),
  });
  if (!res.ok) throw new Error(await res.text());
  const json = await res.json();
  return json.access_token;
}

const token = await getToken();

const customerRes = await fetch("https://api.mvmnt.io/v1/customers", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${token}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    name: "Acme Industrial Plastics",
    status: "ACTIVE",
    website: "https://acme-industrial-plastics.example",
    phoneNumber: "+1-214-555-0199",
  }),
});

if (!customerRes.ok) {
  console.error(await customerRes.text());
  process.exit(1);
}

const customer = await customerRes.json();
console.log({ customerId: customer.id, name: customer.name, status: customer.status });

Run:

node quickstart-customer.mjs

Python

# quickstart_customer.py
import os
import requests

token_res = requests.post(
    "https://api.mvmnt.io/oauth2/token",
    headers={"Content-Type": "application/x-www-form-urlencoded"},
    data={
        "grant_type": "client_credentials",
        "client_id": os.environ["MVMNT_CLIENT_ID"],
        "client_secret": os.environ["MVMNT_CLIENT_SECRET"],
    },
    timeout=30,
)
token_res.raise_for_status()
token = token_res.json()["access_token"]

customer_res = requests.post(
    "https://api.mvmnt.io/v1/customers",
    headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
    json={
        "name": "Acme Industrial Plastics",
        "status": "ACTIVE",
        "website": "https://acme-industrial-plastics.example",
        "phoneNumber": "+1-214-555-0199",
    },
    timeout=30,
)

customer_res.raise_for_status()
customer = customer_res.json()
print({"customerId": customer["id"], "name": customer["name"], "status": customer["status"]})

Run:

python quickstart_customer.py

Step 4: Create pickup and delivery locations

Create two locations under the customer you just created.

Create pickup location (cURL)

Replace CUSTOMER_ID with the customer id from Step 3.

curl -sS -X POST "https://api.mvmnt.io/v1/locations" \
  -H "Authorization: Bearer ${MVMNT_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "customerId": "CUSTOMER_ID",
    "name": "Acme Plastics DC - Dallas, TX",
    "key": "QS-LOC-DAL-001",
    "type": "SHIPPER",
    "isAppointmentRequired": true,
    "notes": "Appointments required. Receiving: Mon-Fri 07:00-15:00",
    "internalNotes": "Check in at gate, then door assignment by radio"
  }'

Expected output (HTTP 201 Created):

{
  "object": "LOCATION",
  "id": "770e8400-e29b-41d4-a716-446655440000",
  "customerId": "550e8400-e29b-41d4-a716-446655440000",
  "name": "Acme Plastics DC - Dallas, TX",
  "key": "QS-LOC-DAL-001",
  "type": "SHIPPER",
  "isAppointmentRequired": true,
  "notes": "Appointments required. Receiving: Mon-Fri 07:00-15:00",
  "internalNotes": "Check in at gate, then door assignment by radio",
  "createdAt": "2026-01-22T18:32:00Z",
  "updatedAt": "2026-01-22T18:32:00Z",
  "deletedAt": null
}

Save the id as PICKUP_LOCATION_ID.

Create delivery location (cURL)

curl -sS -X POST "https://api.mvmnt.io/v1/locations" \
  -H "Authorization: Bearer ${MVMNT_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "customerId": "CUSTOMER_ID",
    "name": "Acme Retail DC - Atlanta, GA",
    "key": "QS-LOC-ATL-001",
    "type": "RECEIVER",
    "isAppointmentRequired": false,
    "notes": "No appointment. Deliveries: Mon-Fri 08:00-16:00"
  }'

Expected output (HTTP 201 Created): same shape as above. Save the id as DELIVERY_LOCATION_ID.

Step 5: Create an order

This creates a draft order with two stops and basic freight details.

cURL

Replace PICKUP_LOCATION_ID and DELIVERY_LOCATION_ID with your location IDs from Step 4.

curl -sS -X POST "https://api.mvmnt.io/v1/orders" \
  -H "Authorization: Bearer ${MVMNT_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "key": "QS-ORDER-2026-0001",
    "stops": [
      { "sequence": 1, "type": "pickup", "locationId": "PICKUP_LOCATION_ID" },
      { "sequence": 2, "type": "delivery", "locationId": "DELIVERY_LOCATION_ID" }
    ],
    "freight": {
      "handlingUnits": 20,
      "handlingUnitType": "pallet",
      "weight": 18400,
      "weightUnit": "lbs"
    }
  }'

Expected output (HTTP 201 Created):

{
  "id": "660e8400-e29b-41d4-a716-446655440001",
  "friendlyId": "ORD-12345",
  "key": "QS-ORDER-2026-0001",
  "status": "draft",
  "stops": [
    { "sequence": 1, "type": "pickup", "locationId": "770e8400-e29b-41d4-a716-446655440000" },
    { "sequence": 2, "type": "delivery", "locationId": "880e8400-e29b-41d4-a716-446655440002" }
  ],
  "freight": {
    "handlingUnits": 20,
    "handlingUnitType": "pallet",
    "weight": 18400,
    "weightUnit": "lbs"
  },
  "createdAt": "2026-01-22T18:35:00Z",
  "updatedAt": "2026-01-22T18:35:00Z"
}

Save friendlyId (example: ORD-12345). You will use it to fetch the order.

JavaScript

// quickstart-order.mjs
async function getToken() {
  const res = await fetch("https://api.mvmnt.io/oauth2/token", {
    method: "POST",
    headers: { "Content-Type": "application/x-www-form-urlencoded" },
    body: new URLSearchParams({
      grant_type: "client_credentials",
      client_id: process.env.MVMNT_CLIENT_ID,
      client_secret: process.env.MVMNT_CLIENT_SECRET,
    }),
  });
  if (!res.ok) throw new Error(await res.text());
  return (await res.json()).access_token;
}

const token = await getToken();

const orderRes = await fetch("https://api.mvmnt.io/v1/orders", {
  method: "POST",
  headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    key: "QS-ORDER-2026-0001",
    stops: [
      { sequence: 1, type: "pickup", locationId: "PICKUP_LOCATION_ID" },
      { sequence: 2, type: "delivery", locationId: "DELIVERY_LOCATION_ID" },
    ],
    freight: { handlingUnits: 20, handlingUnitType: "pallet", weight: 18400, weightUnit: "lbs" },
  }),
});

if (!orderRes.ok) {
  console.error(await orderRes.text());
  process.exit(1);
}

const order = await orderRes.json();
console.log({ orderId: order.id, friendlyId: order.friendlyId, status: order.status, key: order.key });

Run:

node quickstart-order.mjs

Python

# quickstart_order.py
import os
import requests

token_res = requests.post(
    "https://api.mvmnt.io/oauth2/token",
    headers={"Content-Type": "application/x-www-form-urlencoded"},
    data={
        "grant_type": "client_credentials",
        "client_id": os.environ["MVMNT_CLIENT_ID"],
        "client_secret": os.environ["MVMNT_CLIENT_SECRET"],
    },
    timeout=30,
)
token_res.raise_for_status()
token = token_res.json()["access_token"]

order_res = requests.post(
    "https://api.mvmnt.io/v1/orders",
    headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
    json={
        "key": "QS-ORDER-2026-0001",
        "stops": [
            {"sequence": 1, "type": "pickup", "locationId": "PICKUP_LOCATION_ID"},
            {"sequence": 2, "type": "delivery", "locationId": "DELIVERY_LOCATION_ID"},
        ],
        "freight": {
            "handlingUnits": 20,
            "handlingUnitType": "pallet",
            "weight": 18400,
            "weightUnit": "lbs",
        },
    },
    timeout=30,
)

order_res.raise_for_status()
order = order_res.json()
print({"orderId": order.get("id"), "friendlyId": order.get("friendlyId"), "status": order.get("status"), "key": order.get("key")})

Run:

python quickstart_order.py

Step 6: Verify success (fetch by client key)

If you set a unique key on the order, you can pull it back without storing an ID.

curl -sS "https://api.mvmnt.io/v1/orders?key=QS-ORDER-2026-0001" \
  -H "Authorization: Bearer ${MVMNT_TOKEN}"

Expected output (HTTP 200 OK):

{
  "id": "660e8400-e29b-41d4-a716-446655440001",
  "friendlyId": "ORD-12345",
  "key": "QS-ORDER-2026-0001",
  "status": "draft",
  "createdAt": "2026-01-22T18:35:00Z",
  "updatedAt": "2026-01-22T18:35:00Z"
}

Troubleshooting

For error response format and status codes, see Error Handling.

Token request fails

  • 400 with {"error":"invalid_client" ...}

    • Client ID or secret is wrong, or copied with extra whitespace.
    • Re-copy credentials from your MVMNT account manager, then retry.
  • 400 with {"error":"invalid_grant" ...}

    • grant_type must be client_credentials.

API request fails with 401 Unauthorized

Common causes:

  • Missing header: Authorization: Bearer <token>
  • Token expired (default lifetime is 3600 seconds)

Fix:

  • Request a new token, then retry the API request.

Create requests fail with 422 Unprocessable Entity

  • Required fields are missing or field values do not match allowed enums.
  • Print the response body and fix the field called out in error.details.

Create requests fail with 409 Conflict

  • A key must be unique per resource type.
  • Change the key (example: QS-ORDER-2026-0002) and retry.

Requests fail with 429 Too Many Requests

  • You hit the rate limit.
  • Back off and retry after a short delay. Use exponential backoff for automation.

Network or TLS errors

  • Verify you can reach https://api.mvmnt.io from your environment.
  • If you are behind a proxy, configure your HTTP client to use it.