Getting Started with the iDrive Shipping API

The iDrive Shipping API enables you to integrate shipping functionality directly into your applications. Access real-time rates, generate shipping labels, manage carrier accounts, and configure warehouse locations, all through a RESTful API. This guide covers the essentials you need to make your first successful API call.

Before You Begin

To use the iDrive Shipping API, you'll need:

  • API credentials (clientId and clientSecret)
  • Tenant ID for your organization
  • Shipping Site ID for warehouse operations (for rating and label generation) if you have multiple warehouses

Base URLs

Choose the appropriate base URL for your environment:

Sandbox: https://api.beta.idrivelogistics.com

Production: https://api.idrivelogistics.com

All API endpoints are appended to these base URLs (e.g., /api/v1/labels, /api/v1/rates).


Authentication

The iDrive API uses bearer token authentication. Every API request requires:

  1. A valid access token (proves your identity)
  2. A tenant ID header (specifies which organization you're acting on behalf of)

Getting Your API Credentials

API credentials consist of a clientId and clientSecret. You can obtain these in two ways:

  • Request them from your iDrive account administrator
  • Generate them yourself at Settings > API Keys in the iDrive platform

Important: Treat these credentials like passwords. Never expose them in client-side code or public repositories.

Obtaining a Bearer Token

Request a token from the Machine-to-Machine (M2M) authentication endpoint:

Endpoint: POST /api/v1/tokens/m2m

Request Body:

{
  "grantType": "clientCredentials",
  "clientId": "YOUR_CLIENT_ID",
  "clientSecret": "YOUR_CLIENT_SECRET",
  "tenantId": "YOUR_TENANT_ID"
}

Response:

{
  "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "tokenType": "Bearer",
  "expiresIn": 3600,
  "refreshToken": "..."
}

Key Details:

  • Tokens expire after 1 hour (3600 seconds)
  • Use the accessToken in the Authorization header for subsequent requests
  • Request a new token when the current one expires
  • It's best to refresh your bearer token shortly before it expires, about one minute earlier. The old token remains valid for any in-flight requests, while new requests can immediately use the fresh token, preventing avoidable failures.

Making Authenticated Requests

Include your bearer token in the Authorization header of every API call:

Authorization: Bearer YOUR_ACCESS_TOKEN
x-tenant-id: YOUR_TENANT_ID

Understanding Tenants

In iDrive, every organization entity is represented as a tenant:

  • WMS / Channel Partner
    • Tenant type thirdPartyLogisticParent
  • 3PLs / Fulfillment Providers
    • Tenant type thirdPartyLogistic
  • 3PL Client / Brand
    • Tenant type brand

Each tenant has a unique tenantId that must be included in API requests via the x-tenant-id header.

Why Tenant ID Matters

Using the correct tenant ID ensures:

  • Proper access permissions
  • Correct carrier account associations
  • Accurate rate calculations
  • Valid label generation
  • Data consistency

Using an incorrect tenant ID may result in:

  • 403 Permission Denied errors
  • Missing carrier accounts
  • Failed rate requests
  • Label generation errors

Retrieving Tenant Information

Use the Tenants API to discover available tenants:

  • Get all tenants: GET /api/v1/tenants
    • The response will include all tenants and any associated tenant children.
  • Get specific tenant: GET /api/v1/tenants/{tenantId}

For detailed tenant management, see the Tenants API Guide.


Understanding Shipping Sites

A Shipping Site represents a physical warehouse location within a tenant. Some shipping operations require a valid shippingSiteId:

  • Generating a manifest
  • Getting shipping rates
  • Generating shipping labels
  • Managing some carrier accounts

Working with Shipping Sites

Typical workflow:

  1. Create a shipping site for your tenant: POST /api/v1/shippingSites
  2. Retrieve the id from the response and store it
  3. Include this id in your manifest, rate, and label requests in the shippingSiteId field

Retrieve existing sites: GET /api/v1/shippingSites

More details


Quick Start Example

Here's a complete flow to generate a shipping label:

Step 1: Get an Access Token

curl -X POST https://api.beta.idrivelogistics.com/api/v1/tokens/m2m \
  -H "Content-Type: application/json" \
  -d '{
    "grantType": "clientCredentials",
    "clientId": "your_client_id",
    "clientSecret": "your_client_secret",
    "tenantId": "your_tenant_id"
  }'

Step 2: Get Shipping Rates

curl -X POST https://api.beta.idrivelogistics.com/api/v1/rates \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "x-tenant-id: YOUR_TENANT_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "shipment": {
      "shipTo": {
        "company": "string",
        "name": "string",
        "email": "string",
        "phone": "string",
        "addressLine1": "string",
        "addressLine2": "string",
        "addressLine3": "string",
        "city": "string",
        "stateProvince": "string",
        "postalCode": "string",
        "countryCode": "string",
        "isResidential": true
      },
      "shipFrom": {
        "company": "string",
        "name": "string",
        "email": "string",
        "phone": "string",
        "addressLine1": "string",
        "addressLine2": "string",
        "addressLine3": "string",
        "city": "string",
        "stateProvince": "string",
        "postalCode": "string",
        "countryCode": "string",
        "isResidential": true
      },
      "packages": [
        {
          "heightIn": 0,
          "lengthIn": 0,
          "widthIn": 0,
          "weightLbs": 0,
          "type": "box",
          "predefinedPackage": "string",
          "items": [
            {
              "countryOfOrigin": "string",
              "description": "string",
              "harmonizedCode": "string",
              "name": "string",
              "quantity": 0,
              "sku": "string",
              "value": 0,
              "weightLbs": 0,
              "isHazmat": false,
              "hazmatLiquidVolumeOz": 0,
              "hazmatUnNumber": "UN1090",
              "hazmatTransportationRegulatoryClass": "3",
              "hazmatPackingGroup": "I",
              "hazmatPackingInstruction": "PI965_SECTION_IA",
              "hazmatProperShippingName": "string"
            }
          ],
          "contentsType": "merchandise",
          "contentsTypeExplanation": "string",
          "options": {
            "customMessage1": "string",
            "customMessage2": "string",
            "customMessage3": "string",
            "deliveryConfirmation": "ADULT_SIGNATURE",
            "incoTerm": "DAP",
            "dryIceWeight": 0,
            "deliveryOption": "SATURDAY_DELIVERY",
            "specialRatesEligibility": "USPS_LIBRARYMAIL",
            "additionalHandling": true,
            "payment": {
              "type": "SENDER"
            }
          },
          "isHazmat": false
        }
      ],
      "orderReference": "string",
      "returnType": "LABEL",
      "options": {
        "customMessage1": "string",
        "customMessage2": "string",
        "customMessage3": "string",
        "deliveryConfirmation": "ADULT_SIGNATURE",
        "incoTerm": "DAP",
        "dryIceWeight": 0,
        "deliveryOption": "SATURDAY_DELIVERY",
        "specialRatesEligibility": "USPS_LIBRARYMAIL",
        "additionalHandling": true,
        "payment": {
          "type": "SENDER"
        }
      }
    },
    "options": {
      "serviceLevels": [
        "AMAZON_SHIPPING_GROUND",
        "USPS_FIRST_CLASS",
        "FEDEX_GROUND",
        "UPS_GROUND",
        "DHL_ECOM_PARCEL_GROUND",
        "DHL_EXPRESS_EXPRESS_900",
        "EPG_DOMESTIC_PRIORITY_PARCEL",
        "ONTRAC_GROUND",
        "GLS_GROUND"
      ],
      "timeInTransit": "SameDay",
      "carrierAccountIds": [
        "string"
      ]
    }
  }'

Step 3: Create a Label

curl -X POST https://api.beta.idrivelogistics.com/api/v1/labels \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "x-tenant-id: YOUR_TENANT_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "service": "USPS",
    "serviceLevel": "string",
    "orderReference": "string",
    "shipment": {
      "externalOrderId": "string",
      "cartOrderId": "string",
      "wmsIntegrationId": "string",
      "orderSource": "string",
      "batchId": "string",
      "shipTo": {
        "company": "string",
        "name": "string",
        "email": "string",
        "phone": "string",
        "addressLine1": "string",
        "addressLine2": "string",
        "addressLine3": "string",
        "city": "string",
        "stateProvince": "string",
        "postalCode": "string",
        "countryCode": "string",
        "isResidential": true
      },
      "shipFrom": {
        "company": "string",
        "name": "string",
        "email": "string",
        "phone": "string",
        "addressLine1": "string",
        "addressLine2": "string",
        "addressLine3": "string",
        "city": "string",
        "stateProvince": "string",
        "postalCode": "string",
        "countryCode": "string",
        "isResidential": true,
        "siteId": "string"
      },
      "packages": [
        {
          "externalPackageId": "string",
          "heightIn": 0,
          "lengthIn": 0,
          "widthIn": 0,
          "dimWeight": 0,
          "weightLbs": 0,
          "type": "box",
          "predefinedPackage": "string",
          "items": [
            {
              "countryOfOrigin": "string",
              "description": "string",
              "harmonizedCode": "string",
              "name": "string",
              "quantity": 0,
              "sku": "string",
              "value": 0,
              "weightLbs": 0,
              "isHazmat": false,
              "hazmatLiquidVolumeOz": 0,
              "hazmatUnNumber": "UN1090",
              "hazmatTransportationRegulatoryClass": "3",
              "hazmatPackingGroup": "I",
              "hazmatPackingInstruction": "PI965_SECTION_IA",
              "hazmatProperShippingName": "string"
            }
          ],
          "contentsType": "merchandise",
          "contentsTypeExplanation": "string",
          "options": {
            "customMessage1": "string",
            "customMessage2": "string",
            "customMessage3": "string",
            "deliveryConfirmation": "ADULT_SIGNATURE",
            "incoTerm": "DAP",
            "dryIceWeight": 0,
            "deliveryOption": "SATURDAY_DELIVERY",
            "specialRatesEligibility": "USPS_LIBRARYMAIL",
            "additionalHandling": true,
            "payment": {
              "type": "SENDER"
            }
          },
          "isHazmat": false
        }
      ],
      "returnType": "LABEL"
    },
    "rateQuoteId": "string",
    "rateOptions": {
      "serviceLevels": [
        "AMAZON_SHIPPING_GROUND",
        "USPS_FIRST_CLASS",
        "FEDEX_GROUND",
        "UPS_GROUND",
        "DHL_ECOM_PARCEL_GROUND",
        "DHL_EXPRESS_EXPRESS_900",
        "EPG_DOMESTIC_PRIORITY_PARCEL",
        "ONTRAC_GROUND",
        "GLS_GROUND"
      ],
      "timeInTransit": "SameDay",
      "carrierAccountIds": [
        "string"
      ]
    },
    "carrierAccountId": "string",
    "labelOptions": {
      "type": "ZPL",
      "size": "4x6",
      "inline": true
    },
    "mode": "TEST"
  }'

Next Steps

Now that you understand authentication and core concepts, explore these API capabilities:

Rates API — Compare shipping rates across carriers

Labels API — Generate and manage shipping labels

Carrier Accounts API — Connect and manage your carrier accounts

Create Carrier Account — Add your own carrier credentials

Tenants API — Manage organizational structure

Shipping Sites API — Configure warehouse locations


Need Help?


Best Practices

Secure your credentials — Never commit API keys to version control

Handle token expiration — Implement automatic token refresh logic

Use the correct tenant ID — Verify you're using the right tenant for each operation

Test in sandbox first — Always develop against the sandbox environment

Cache tokens — Reuse valid tokens instead of requesting new ones for every call