> 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.

# List carriers

GET https://tryenvoy.ai/api/v1/carriers

List carriers with pagination and optional search by name, MC#, or DOT#. When `ids` is set, returns exactly those carriers (org-scoped) and every other filter is ignored — an exact-set fetch for client-side hydration overlays. Otherwise supports two verdict-filter modes that coexist on this endpoint:

* **Operational mode** (default) — `verdict` / `verified_date_*` filter on current `Carrier.is_verified` + `verified_date` state.
* **Audit-table mode** — when `latest_status` is set (with required `since` + `until`), filter carriers whose **latest** `carrier_verifications` row inside the window matches that status. Uses the same latest-per-subject window query as the scorecard Compliance & Risk tiles, but lists only *persisted* carriers: audit rows anchored to a subject identifier (a blocked party never saved as a Carrier row) count in the tiles and have no row to show here — the tile responses carry a `never_persisted` split for exactly that difference. `verdict` / `verified_date_*` are ignored in this mode.

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

Reference: https://docs.tryenvoy.ai/api-reference/endpoints/carriers/list

## 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

### Query parameters

- `ids` (string, optional, nullable) — Comma-separated carrier ids (prefixed `car_…` or raw UUIDs), max 100. When set, returns exactly those carriers (unknown ids are omitted) and every other filter/pagination param is ignored.
- `search` (string, optional, nullable) — Search by name, MC#, DOT#
- `origin_city` (string, optional, nullable) — Only carriers with an active lane preference from this city
- `origin_state` (string, optional, nullable) — Two-letter state for origin_city
- `destination_city` (string, optional, nullable) — Narrow the lane filter to this destination city
- `destination_state` (string, optional, nullable) — Two-letter state for destination_city
- `equipment_types` (list of enum, optional, nullable) — Repeatable: only carriers that can haul AT LEAST ONE of these equipment types. Carriers with no equipment recorded never match.
  - 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`
- `routing_guide_tier` (list of integer, optional, nullable) — Repeatable: only carriers whose GLOBAL routing-guide tier is one of these (1-4). Untiered never matches. Range is checked in the handler — `ge`/`le` on a repeatable param is applied to the LIST by pydantic and raises rather than validating the items.
- `is_active` (boolean, optional, nullable, default: true) — Filter by active status
- `verdict` (string, optional, nullable) — Filter by compliance verdict (PASSED | BLOCKED | UNVERIFIED)
- `verified_date_start` (date, optional, nullable) — Filter carriers verified on/after this date. Mirrors the scorecard's verdict-breakdown period bucketing on Carrier.verified_date.
- `verified_date_end` (date, optional, nullable) — Filter carriers verified on/before this date. Mirrors the scorecard's verdict-breakdown period bucketing on Carrier.verified_date.
- `latest_status` (string, optional, nullable) — Audit-table mode switch. Filter carriers whose latest `carrier_verifications` row in [since, until] has this status (PASSED | BLOCKED | UNVERIFIED | errored | rejected). `errored` selects carriers whose latest verification has no verdict (provider outage / pipeline error); `rejected` selects a determinate rejection (BLOCKED or UNVERIFIED) — the combined set behind the rejection-reasons drill-down. Requires `since` and `until` to be set. When this is set, `verdict` and `verified_date_*` are ignored.
- `since` (date, optional, nullable) — Inclusive lower bound for audit-table mode (`carrier_verifications.created_at`).
- `until` (date, optional, nullable) — Inclusive upper bound for audit-table mode (`carrier_verifications.created_at`).
- `verification_source` (enum, optional, nullable) — Optional source filter for audit-table mode (api | extension | truck_list_email | voice_call | chat_tool). Mirrors the scorecard's source dropdown.
  - Allowed values: `api`, `csv_import`, `extension`, `truckstop_hot_prospects`, `truck_list_email`, `voice_call`, `chat_tool`, `email_outreach`, `inbound_email`, `revanova_tms`, `tai_tms`, `inbound_whatsapp`, `whatsapp_outreach`, `edge_tms`
- `sort_by` (enum, optional) — Column to sort by. `last_verified_at` orders on the same figure the response returns (latest non-drop verification), not on `verified_date`. `equipment_types` groups carriers by their equipment as rendered.
  - Allowed values: `name`, `status`, `equipment_types`, `verification_status`, `last_verified_at`, `routing_guide_tier`, `total_loads_hauled`, `on_time_delivery_pct`, `tms_status`, `carrier_rep`
- `sort_order` (enum, optional) — Sort direction
  - Allowed values: `asc`, `desc`
- `page` (integer, optional, default: 1) — Page number
- `page_size` (integer, optional, default: 20) — Results per page

### Headers

- `X-Organization-ID` (string, optional, nullable)

## Response

### 200

Successful Response

- `data` (list of CarrierResponse, required) — List of items for the current page
- `pagination` (PaginationInfo, required) — Pagination metadata

## Errors

### 401 Unauthorized Error

Not authenticated - missing or invalid token/API key

- `any`

### 403 Forbidden Error

Insufficient permissions for this operation

- `any`

### 422 Unprocessable Entity Error

Validation Error

- `detail` (list of ValidationError, optional)

### 429 Too Many Requests Error

Rate limit exceeded - see Retry-After header

- `any`

## Types

### CarrierResponse

v1 carrier response - wraps domain CarrierModel with prefixed IDs.

- `id` (string, required)
- `name` (string, required)
- `mc_number` (string, optional, nullable)
- `dot_number` (string, optional, nullable)
- `email` (string, optional, nullable)
- `phone` (string, optional, nullable)
- `dispatcher_name` (string, optional, nullable)
- `dispatcher_phone` (string, optional, nullable)
- `dispatcher_email` (string, optional, nullable)
- `is_active` (boolean, optional, default: true)
- `tms_status` (string, optional, nullable) — Carrier status as reported by the source TMS (e.g. DNL). Read by the inbound email gate when the organization opts in to operational restriction notices for inactive carriers with this status.
- `provider` (string, optional, nullable)
- `ingestion_method` (string, optional, nullable)
- `equipment_types` (list of enum, optional, nullable)
  - 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`
- `insurance_expiration` (datetime, optional, nullable)
- `w9_on_file` (boolean, optional, nullable)
- `authorized_for_hire` (boolean, optional, nullable)
- `on_time_pickup_pct` (double, optional, nullable) — On-time pickup percentage (0-100 scale)
- `on_time_delivery_pct` (double, optional, nullable) — On-time delivery percentage (0-100 scale)
- `tracking_compliance_pct` (double, optional, nullable)
- `avg_response_time_min` (double, optional, nullable)
- `total_loads_hauled` (integer, optional, nullable)
- `is_onboarded` (boolean, optional, default: false)
- `routing_guide_tier` (integer, optional, nullable) — Global routing-guide priority tier (1 = highest, 4 = lowest). None = untiered.
- `lane_routing_guide_tier` (integer, optional, nullable) — Strongest routing-guide tier this carrier holds on the lane the list was filtered to (1 = highest). Null when the list has no lane filter, or the carrier is untiered on it.
- `effective_routing_guide_tier` (integer, optional, nullable) — The tier that actually applies: `lane_routing_guide_tier` when set, else `routing_guide_tier`. Equal to the global tier on an unfiltered list.
- `carrier_rep_user_id` (string, optional, nullable)
- `carrier_rep_name` (string, optional, nullable)
- `carrier_rep_email` (string, optional, nullable)
- `is_verified` (boolean, optional, default: false)
- `verified_date` (datetime, optional, nullable)
- `compliance_status` (enum, optional) — The verdict of Envoy's most recent compliance check on the carrier: PASSED or BLOCKED, or UNVERIFIED when no check has run yet or the last check could not reach a result.
  - Allowed values: `PASSED`, `BLOCKED`, `UNVERIFIED`
- `stop_contact_requested_at` (datetime, optional, nullable) — When the carrier last asked not to be contacted; Envoy stops contacting them
- `tms_carrier_id` (string, optional, nullable) — The carrier's ID in your TMS
- `last_verified_at` (datetime, optional, nullable)
- `last_verified_provider` (string, optional, nullable) — Which compliance provider issued the most recent verification (e.g. Highway or MyCarrierPackets). Distinct from `provider`, which is the system the carrier record came from. Null when no verification has run, or when the provider was not recorded.
- `created_at` (datetime, optional, nullable)
- `updated_at` (datetime, optional, nullable)

### PaginationInfo

Standardized pagination information model

- `page` (integer, required) — Current page number (1-based)
- `page_size` (integer, required) — Number of items per page
- `total_count` (integer, required) — Total number of items
- `total_pages` (integer, required) — Total number of pages
- `has_next` (boolean, required) — Whether there's a next page
- `has_prev` (boolean, required) — Whether there's a previous page

### ValidationError

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

### ValidationErrorLocItems

### ValidationErrorCtx

## Examples

**Response**

```json
{
  "data": [
    {
      "id": "car_00000000-0000-0000-0000-000000000000",
      "name": "string",
      "mc_number": "string",
      "dot_number": "string",
      "email": "string",
      "phone": "string",
      "dispatcher_name": "string",
      "dispatcher_phone": "string",
      "dispatcher_email": "string",
      "is_active": true,
      "tms_status": "string",
      "provider": "string",
      "ingestion_method": "string",
      "equipment_types": [
        "VAN"
      ],
      "insurance_expiration": "2024-01-15T09:30:00Z",
      "w9_on_file": true,
      "authorized_for_hire": true,
      "on_time_pickup_pct": 1.1,
      "on_time_delivery_pct": 1.1,
      "tracking_compliance_pct": 1.1,
      "avg_response_time_min": 1.1,
      "total_loads_hauled": 1,
      "is_onboarded": false,
      "routing_guide_tier": 1,
      "lane_routing_guide_tier": 1,
      "effective_routing_guide_tier": 1,
      "carrier_rep_user_id": "usr_00000000-0000-0000-0000-000000000000",
      "carrier_rep_name": "string",
      "carrier_rep_email": "string",
      "is_verified": false,
      "verified_date": "2024-01-15T09:30:00Z",
      "compliance_status": "PASSED",
      "stop_contact_requested_at": "2024-01-15T09:30:00Z",
      "tms_carrier_id": "string",
      "last_verified_at": "2024-01-15T09:30:00Z",
      "last_verified_provider": "string",
      "created_at": "2024-01-15T09:30:00Z",
      "updated_at": "2024-01-15T09:30:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "page_size": 1,
    "total_count": 1,
    "total_pages": 1,
    "has_next": true,
    "has_prev": true
  }
}
```

**SDK Code**

```python
import requests

url = "https://tryenvoy.ai/api/v1/carriers"

headers = {"Authorization": "Bearer <token>"}

response = requests.get(url, headers=headers)

print(response.json())
```

```javascript
const url = 'https://tryenvoy.ai/api/v1/carriers';
const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};

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"
	"net/http"
	"io"
)

func main() {

	url := "https://tryenvoy.ai/api/v1/carriers"

	req, _ := http.NewRequest("GET", url, nil)

	req.Header.Add("Authorization", "Bearer <token>")

	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/carriers")

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

request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'

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.get("https://tryenvoy.ai/api/v1/carriers")
  .header("Authorization", "Bearer <token>")
  .asString();
```

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

$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'https://tryenvoy.ai/api/v1/carriers', [
  'headers' => [
    'Authorization' => 'Bearer <token>',
  ],
]);

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

```csharp
using RestSharp;

var client = new RestClient("https://tryenvoy.ai/api/v1/carriers");
var request = new RestRequest(Method.GET);
request.AddHeader("Authorization", "Bearer <token>");
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = ["Authorization": "Bearer <token>"]

let request = NSMutableURLRequest(url: NSURL(string: "https://tryenvoy.ai/api/v1/carriers")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers

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()
```