> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.tryenvoy.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.tryenvoy.ai/_mcp/server.

# Batch create loads

POST https://tryenvoy.ai/api/v1/loads/batch
Content-Type: application/json

Create multiple freight loads in a single request. Each load is processed independently. Accepts API-key or session/bearer auth so both integrations and the web app (CSV upload) can call it.

**Authentication:** Supports API key and bearer token authentication.

Reference: https://docs.tryenvoy.ai/api-reference/endpoints/loads/batch-create

## Authentication

- `Authorization` header (bearer token, required) — Bearer authentication of the form `Bearer <token>`, where token is your auth token.

## Servers

- `https://tryenvoy.ai/api/v1` (Production, default)
- `https://staging.tryenvoy.ai/api/v1` (Staging)

## Request

### Headers

- `X-Organization-ID` (string, optional, nullable)
- `X-CSV-Import-ID` (string, optional, nullable) — Browser-generated UUID correlating every chunk of one CSV import attempt
- `X-CSV-Chunk-Index` (string, optional, nullable) — 1-based position of this chunk within the import
- `X-CSV-Chunk-Count` (string, optional, nullable) — Total number of chunks in the import
- `Idempotency-Key` (string, optional) — A unique key (up to 255 printable ASCII characters, e.g. a UUID) that makes a retry of this request safe. Envoy stores the response for 24 hours; a retry with the same key and the same request returns it again with `Idempotent-Replayed: true` instead of running twice. The same key with a different request returns 422 `idempotency_key_reused`; while the first request is still running, 409 `idempotency_key_in_progress`. 5xx and 429 responses are not stored.

### Body (application/json)

This endpoint expects a TMSLoadBatchRequest.

- `loads` (list of TMSLoadRequest, required) — List of TMS loads to ingest (max 1000 per batch)
- `generate_demo_carriers` (boolean, optional, default: false) — Generate deterministic carrier and lane-preference demo data for successfully ingested loads

## Response

### 200

Successful Response

- `success` (boolean, required) — True if at least one load was processed successfully
- `total_loads` (integer, required) — Total number of loads in the batch
- `successful` (integer, required) — Number of loads processed successfully
- `failed` (integer, required) — Number of loads that failed to process
- `created` (integer, required) — Number of new loads created
- `updated` (integer, required) — Number of existing loads updated
- `results` (list of TMSLoadBatchResult, required) — Detailed results for each load
- `processed_at` (datetime, required) — Timestamp when batch was processed
- `generation` (TMSLoadDemoGenerationResult, optional) — Carrier and lane-preference generation results
- `backend_duration_ms` (double, optional, nullable) — Server processing time for this CSV import chunk, when correlation headers are supplied
- `data` (list of BatchItemResult, optional) — One result per submitted load, in request order
- `summary` (BatchSummary, optional, nullable) — Counts by outcome, with skipped rows separate

### 207

Some items were not applied; each one's reason is in data[].error (or errors[])

## Errors

### 401 Unauthorized Error

Not authenticated - missing or invalid token/API key

- `any`

### 403 Forbidden Error

Insufficient permissions for this operation

- `any`

### 409 Conflict Error

`idempotency_key_in_progress`: a request with this Idempotency-Key is still running; retry later

- `any`

### 422 Unprocessable Entity Error

Validation Error; or `idempotency_key_reused`: this Idempotency-Key was already used for a different request

- `detail` (list of ValidationError, optional)

### 429 Too Many Requests Error

Rate limit exceeded - see Retry-After header

- `any`

## Types

### TMSLoadRequest

Request model for TMS load ingestion

- `load_number` (string, required) — Unique load reference number
- `equipment_type` (enum, required) — Equipment type used for transport
  - Allowed values: `VAN`, `REEFER`, `FLATBED`, `STEPDECK`, `RGN`, `CONESTOGA`, `BOX_TRUCK`, `CONTAINER`, `INTERMODAL`, `POWER_ONLY`, `TANKER`, `LOWBOY`, `HOTSHOT`, `AUTO_CARRIER`, `DRY_BULK`, `DRY_TEAM`, `REEFER_TEAM`, `LTL`, `OTHER`, `VAN/REEFER`
- `stops` (list of Stop, required) — Ordered list of stops (pickup and dropoff) - minimum 2 required
- `equipment_type_raw` (string, optional, nullable) — Original equipment-type string from the source TMS (e.g. 'Van/Reefer 53'', 'Dry Van 53FT'). Stored verbatim for audit; not used for matching.
- `mode` (enum, optional, nullable) — Transport mode, when supplied by the source
  - Allowed values: `FTL`, `PTL`, `LTL`, `DED`, `RAIL`, `PASS`
- `tms_load_id` (string, optional, nullable) — Your TMS's ID for the load. Envoy matches updates on it (then on load_number), so keep it stable for the life of the load.
- `tms_status` (string, optional, nullable) — Status supplied by the source TMS; no status is inferred when omitted
- `weight` (double, optional, nullable) — Weight of the load (must be non-negative)
- `distance` (double, optional, nullable) — Number of miles to drive (must be non-negative)
- `commodity` (string, optional, nullable) — Commodity being hauled
- `handling_unit_count` (integer, optional, nullable) — Number of freight handling units
- `handling_unit_type` (string, optional, nullable) — Type of freight handling unit, e.g. pallet or case
- `po_numbers` (list of string, optional, nullable) — List of PO or pickup numbers
- `reference_numbers` (list of ReferenceNumber, optional, nullable) — Typed reference numbers for the load, as sent by the source TMS. po_numbers remains the PO-only projection used by matching/search.
- `posted_rate` (integer, optional, nullable) — Posted rate in USD
- `max_buy_rate` (integer, optional, nullable) — Maximum buy rate in USD
- `suggested_market_rate` (integer, optional, nullable) — Suggested market rate in USD
- `length_feet` (integer, optional, nullable) — Length in feet (must be non-negative)
- `carrier_completed_rate` (double, optional, nullable) — Rate the carrier completed the load at, in USD
- `customer_rate` (double, optional, nullable) — Rate quoted to the customer, in USD
- `margin` (double, optional, nullable) — Margin in USD as reported by the source TMS
- `hold_load` (boolean, optional, default: false) — Whether the source TMS has this load on hold; held loads are hidden from web/extension
- `action` (enum, optional, nullable) — Caller intent for this row (CSV upload). NEW = create (error if it already exists); UPDATE = update (error if it does not exist); INACTIVATE = update + hold_load=true. When omitted, the row is upserted (legacy behavior).
  - Allowed values: `NEW`, `UPDATE`, `INACTIVATE`
- `temperature_setting_minimum` (integer, optional, nullable) — Minimum temperature setting in degrees
- `temperature_setting_maximum` (integer, optional, nullable) — Maximum temperature setting in degrees
- `temperature_run_type` (string, optional, nullable) — Temperature run type (e.g., continuous, cycle)
- `last_reported_state` (string, optional, nullable) — Last reported state for tracking
- `last_reported_city` (string, optional, nullable) — Last reported city for tracking
- `last_reported_long` (double, optional, nullable) — Last reported longitude (-180 to 180, nullable when not moving)
- `last_reported_lat` (double, optional, nullable) — Last reported latitude (-90 to 90, nullable when not moving)
- `tms_carrier_id` (string, optional, nullable) — Your TMS's ID for the carrier hauling the load
- `carrier_name` (string, optional, nullable) — Name of the carrier
- `customer_name` (string, optional, nullable) — Name of the customer (shipper)
- `customer_ref` (string, optional, nullable) — Customer/shipper entity identifier from the TMS (the scheduling feed's customer_tms_id) — not a per-shipment reference number
- `tms_sales_rep_names` (string, optional, nullable) — Sales representative name(s) reported by the source TMS; not an Envoy user assignment
- `carrier_rep` (Contact, optional, nullable) — Carrier Sales Representative contact details
- `driver` (Contact, optional, nullable) — Driver contact details
- `special_instructions` (list of string, optional, nullable) — Special handling instructions provided by the shipper/broker; verbalized to carriers during voice calls
- `notes` (string, optional, nullable) — Internal notes for the load. Shown in Envoy; the AI agent reads them only if your organization turns that on (carrier-facing text belongs in special_instructions).
- `custom_fields` (map from string to any, optional, nullable) — Additional custom fields for source-specific data

### TMSLoadBatchResult

Individual load result within a batch operation. Used by the v1 frontend ``POST /api/v1/loads/batch`` endpoint. The TMS ingest endpoint at ``/api/loads/ingest-tms-loads-batch`` no longer returns per-row results — it acks via ``TMSLoadBatchAckResponse`` and writes outcomes to Datadog instead.

- `load_identifier` (string, required) — Load number or TMS ID for identification
- `success` (boolean, required) — Whether this load was processed successfully
- `load_id` (string, optional, nullable) — UUID of the created/updated load
- `operation` (string, optional, nullable) — Operation performed: 'created' or 'updated'
- `error` (string, optional, nullable) — Error message if processing failed
- `error_code` (string, optional, nullable) — Machine-readable code when processing failed

### TMSLoadDemoGenerationResult

Supporting demo data generated after successful load ingestion.

- `enabled` (boolean, optional, default: false) — Whether demo carrier generation was requested
- `carriers_created` (integer, optional, default: 0) — Number of carriers created
- `carriers_updated` (integer, optional, default: 0) — Number of existing carriers upserted
- `preferences_created` (integer, optional, default: 0) — Number of lane preferences created
- `preferences_updated` (integer, optional, default: 0) — Number of existing lane preferences upserted
- `failed` (integer, optional, default: 0) — Number of generation failures
- `errors` (list of string, optional) — Generation errors; ingested loads are retained

### BatchItemResult

The outcome for one item of a batch request.

- `index` (integer, required) — Position of the item in the request array (0-based)
- `status` (enum, required) — What happened to one submitted item.
  - Allowed values: `created`, `updated`, `skipped`, `failed`
- `id` (string, optional, nullable) — Envoy ID of the created or updated resource (prefixed)
- `external_id` (string, optional, nullable) — The caller's own ID for the item (tms_load_id / tms_carrier_id), echoed back
- `error` (ErrorDetail, optional, nullable) — Why the item failed or was skipped; null when it was created or updated

### BatchSummary

Counts across a batch. ``created + updated + skipped + failed == total``.

- `total` (integer, required)
- `created` (integer, required)
- `updated` (integer, required)
- `skipped` (integer, required)
- `failed` (integer, required)

### ValidationError

- `loc` (list of ValidationErrorLocItems, required)
- `msg` (string, required)
- `type` (string, required)
- `input` (any, optional)
- `ctx` (ValidationErrorCtx, optional)

### Stop

Stop information including location, timing, and contacts

- `location` (Location, required) — Location details of the stop
- `id` (string, optional, nullable) — Envoy's id for the stop (a UUID), set on every stop Envoy returns. Never send your own stop identifier here: put it in pickup_delivery_number or reference_numbers.
- `stop_number` (integer, optional, nullable) — Sequence number of the stop
- `is_pickup` (boolean, optional, nullable) — True if this stop is a pickup
- `is_dropoff` (boolean, optional, nullable) — True if this stop is a dropoff
- `expected_date` (datetime, optional, nullable) — Expected date of activity at this stop
- `contact` (Contact, optional, nullable) — Contact details at the stop (singular, for backward compatibility)
- `type` (enum, optional, nullable) — Type of stop: exactly `Pickup` or `Dropoff` (case-sensitive; other spellings are rejected)
  - Allowed values: `Pickup`, `Dropoff`
- `planned` (PlannedArrival, optional, nullable) — Planned arrival window
- `pickup_delivery_number` (string, optional, nullable) — PO or pickup number; also the place for the source TMS's own stop identifier
- `contacts` (list of Contact, optional, nullable) — List of contacts at this stop
- `actual_stop_times` (ActualStopTimes, optional, nullable) — Actual arrival and departure times
- `carrier_eta` (datetime, optional, nullable) — Carrier's estimated time of arrival
- `reference_numbers` (list of ReferenceNumber, optional, nullable) — Typed reference numbers for this stop, as sent by the source TMS
- `notes` (string, optional, nullable) — Stop notes from the source TMS. DISPLAY ONLY — kept out of the voice/email agent context; carrier-facing text belongs in special_instructions.
- `special_instructions` (list of string, optional, nullable) — Stop-level handling instructions (titled sections), verbalized to carriers

### ReferenceNumber

One typed reference number from a source TMS (stop- or load-level). ``type`` is the source's own label ("Shipper Reference Number", "PO Number", "Shipment Id", ...) kept as display text rather than an enum: every TMS names these differently and customers define their own beyond any standard table, so an enum would silently drop the custom ones. Callers that need typed routing resolve the label at the source boundary (see ``tai/reference_types.py``) and keep the raw string here.

- `value` (string, required) — The reference number itself
- `type` (string, optional, nullable) — Source TMS label for this reference (display text)

### Contact

Contact information for various parties involved in the load

- `type` (enum, optional, nullable) — Role of the contact (for TMS compatibility)
  - Allowed values: `CARRIER`, `DISPATCHER`, `DRIVER`, `TENDERING`, `QUOTING`, `OTHER`
- `first_name` (string, optional, nullable) — First name of the contact
- `last_name` (string, optional, nullable) — Last name of the contact
- `phone` (string, optional, nullable) — Phone number — stored as E.164 when parseable, None otherwise
- `email` (string, optional, nullable) — Email address

### ErrorDetail

Structured error detail for v1 API responses. Machine-readable error codes allow clients to switch on error.code instead of parsing human-readable messages. Example response: \{ "error": \{ "code": "offer\_already\_accepted", "message": "Only one offer can be accepted per load.", "param": null } }

- `code` (string, required) — Machine-readable error code (e.g., 'not_found', 'validation_error')
- `message` (string, required) — Human-readable error description
- `param` (string, optional, nullable) — The request parameter that caused the error, if applicable

### ValidationErrorLocItems

### ValidationErrorCtx

### Location

Location information for stops

- `city` (string, required) — City of the location
- `state` (string, required) — State or province code
- `street` (string, optional, nullable) — Street address of the location
- `postal_code` (string, optional, nullable) — Postal or ZIP code
- `country` (string, optional, nullable, default: US) — Country code (ISO-3166-1 alpha-2), defaults to US
- `company_name` (string, optional, nullable) — Company name at this location
- `county` (string, optional, nullable) — County name
- `latitude` (double, optional, nullable) — Latitude coordinate (-90 to 90)
- `longitude` (double, optional, nullable) — Longitude coordinate (-180 to 180)

### PlannedArrival

Planned arrival window for a stop

- `start` (datetime, optional, nullable) — Earliest arrival time
- `end` (datetime, optional, nullable) — Latest arrival time

### ActualStopTimes

Actual stop times for tracking when arrival/departure occurred

- `arrival_datetime` (datetime, optional, nullable) — Actual arrival timestamp
- `departure_datetime` (datetime, optional, nullable) — Actual departure timestamp

## Examples

### Example 1

**Request**

```json
{
  "loads": [
    {
      "load_number": "string",
      "equipment_type": "VAN",
      "stops": [
        {
          "location": {
            "city": "string",
            "state": "string"
          }
        }
      ]
    }
  ]
}
```

**Response**

```json
{
  "success": true,
  "total_loads": 1,
  "successful": 1,
  "failed": 1,
  "created": 1,
  "updated": 1,
  "results": [
    {
      "load_identifier": "string",
      "success": true,
      "load_id": "string",
      "operation": "string",
      "error": "string",
      "error_code": "string"
    }
  ],
  "processed_at": "2024-01-15T09:30:00Z",
  "generation": {
    "enabled": false,
    "carriers_created": 0,
    "carriers_updated": 0,
    "preferences_created": 0,
    "preferences_updated": 0,
    "failed": 0,
    "errors": [
      "string"
    ]
  },
  "backend_duration_ms": 1.1,
  "data": [
    {
      "index": 1,
      "status": "created",
      "id": "string",
      "external_id": "string",
      "error": {
        "code": "string",
        "message": "string",
        "param": "string"
      }
    }
  ],
  "summary": {
    "total": 1,
    "created": 1,
    "updated": 1,
    "skipped": 1,
    "failed": 1
  }
}
```

**SDK Code**

```python
import requests

url = "https://tryenvoy.ai/api/v1/loads/batch"

payload = { "loads": [
        {
            "load_number": "string",
            "equipment_type": "VAN",
            "stops": [{ "location": {
                        "city": "string",
                        "state": "string"
                    } }]
        }
    ] }
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript
const url = 'https://tryenvoy.ai/api/v1/loads/batch';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"loads":[{"load_number":"string","equipment_type":"VAN","stops":[{"location":{"city":"string","state":"string"}}]}]}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://tryenvoy.ai/api/v1/loads/batch"

	payload := strings.NewReader("{\n  \"loads\": [\n    {\n      \"load_number\": \"string\",\n      \"equipment_type\": \"VAN\",\n      \"stops\": [\n        {\n          \"location\": {\n            \"city\": \"string\",\n            \"state\": \"string\"\n          }\n        }\n      ]\n    }\n  ]\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://tryenvoy.ai/api/v1/loads/batch")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"loads\": [\n    {\n      \"load_number\": \"string\",\n      \"equipment_type\": \"VAN\",\n      \"stops\": [\n        {\n          \"location\": {\n            \"city\": \"string\",\n            \"state\": \"string\"\n          }\n        }\n      ]\n    }\n  ]\n}"

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://tryenvoy.ai/api/v1/loads/batch")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"loads\": [\n    {\n      \"load_number\": \"string\",\n      \"equipment_type\": \"VAN\",\n      \"stops\": [\n        {\n          \"location\": {\n            \"city\": \"string\",\n            \"state\": \"string\"\n          }\n        }\n      ]\n    }\n  ]\n}")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://tryenvoy.ai/api/v1/loads/batch', [
  'body' => '{
  "loads": [
    {
      "load_number": "string",
      "equipment_type": "VAN",
      "stops": [
        {
          "location": {
            "city": "string",
            "state": "string"
          }
        }
      ]
    }
  ]
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://tryenvoy.ai/api/v1/loads/batch");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"loads\": [\n    {\n      \"load_number\": \"string\",\n      \"equipment_type\": \"VAN\",\n      \"stops\": [\n        {\n          \"location\": {\n            \"city\": \"string\",\n            \"state\": \"string\"\n          }\n        }\n      ]\n    }\n  ]\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = ["loads": [
    [
      "load_number": "string",
      "equipment_type": "VAN",
      "stops": [["location": [
            "city": "string",
            "state": "string"
          ]]]
    ]
  ]] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://tryenvoy.ai/api/v1/loads/batch")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

### Example 2

**Request**

```json
{
  "loads": [
    {
      "load_number": "string",
      "equipment_type": "VAN",
      "stops": [
        {
          "location": {
            "city": "string",
            "state": "string"
          }
        }
      ]
    }
  ]
}
```

**Response**

```json
{}
```

**SDK Code**

```python
import requests

url = "https://tryenvoy.ai/api/v1/loads/batch"

payload = { "loads": [
        {
            "load_number": "string",
            "equipment_type": "VAN",
            "stops": [{ "location": {
                        "city": "string",
                        "state": "string"
                    } }]
        }
    ] }
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript
const url = 'https://tryenvoy.ai/api/v1/loads/batch';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"loads":[{"load_number":"string","equipment_type":"VAN","stops":[{"location":{"city":"string","state":"string"}}]}]}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://tryenvoy.ai/api/v1/loads/batch"

	payload := strings.NewReader("{\n  \"loads\": [\n    {\n      \"load_number\": \"string\",\n      \"equipment_type\": \"VAN\",\n      \"stops\": [\n        {\n          \"location\": {\n            \"city\": \"string\",\n            \"state\": \"string\"\n          }\n        }\n      ]\n    }\n  ]\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://tryenvoy.ai/api/v1/loads/batch")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"loads\": [\n    {\n      \"load_number\": \"string\",\n      \"equipment_type\": \"VAN\",\n      \"stops\": [\n        {\n          \"location\": {\n            \"city\": \"string\",\n            \"state\": \"string\"\n          }\n        }\n      ]\n    }\n  ]\n}"

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://tryenvoy.ai/api/v1/loads/batch")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"loads\": [\n    {\n      \"load_number\": \"string\",\n      \"equipment_type\": \"VAN\",\n      \"stops\": [\n        {\n          \"location\": {\n            \"city\": \"string\",\n            \"state\": \"string\"\n          }\n        }\n      ]\n    }\n  ]\n}")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://tryenvoy.ai/api/v1/loads/batch', [
  'body' => '{
  "loads": [
    {
      "load_number": "string",
      "equipment_type": "VAN",
      "stops": [
        {
          "location": {
            "city": "string",
            "state": "string"
          }
        }
      ]
    }
  ]
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://tryenvoy.ai/api/v1/loads/batch");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"loads\": [\n    {\n      \"load_number\": \"string\",\n      \"equipment_type\": \"VAN\",\n      \"stops\": [\n        {\n          \"location\": {\n            \"city\": \"string\",\n            \"state\": \"string\"\n          }\n        }\n      ]\n    }\n  ]\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = ["loads": [
    [
      "load_number": "string",
      "equipment_type": "VAN",
      "stops": [["location": [
            "city": "string",
            "state": "string"
          ]]]
    ]
  ]] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://tryenvoy.ai/api/v1/loads/batch")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```