← Documentation hub

Public Lead Capture

Use this endpoint to post freight leads from your website or quoting form into this Dispatchly tenant. There is no login. You need three things: this tenant’s capture URL, this tenant’s ID, and your website origin on the allowlist.

Piece What Where How
Capture URL Public POST endpoint that creates a lead This page, in the box below. Unique to this tenant’s API host Send JSON to that URL. No Authorization header.
Tenant ID UUID that identifies this brokerage Dispatchly Profile → Account → Tenant ID (Admin / Sub Admin only) Copy it, then send it on every request as x-tenant-id.
Website origin The public site that is allowed to submit leads Settings → source origins, or a Team’s Source origins Send it as Origin. Browsers set this automatically.
JSON body Vehicle or other freight, plus contact / lane fields Your form or backend See the field table and copy a sample in your language.
This tenant’s capture URL
/api/v1/public/leads/capture
Required headers
Content-Type: application/json
x-tenant-id: YOUR_TENANT_ID
Origin: https://www.yourcompany.com

1. Get this tenant’s ID

  1. Ask an Admin or Sub Admin to sign in to Dispatchly.
  2. Open Profile in the left sidebar (selected in red below).
  3. On the Account card, find Tenant ID (the red underlined value).
  4. Click that value to copy the UUID.
  5. Put that UUID in the x-tenant-id header on every capture request. Replace YOUR_TENANT_ID in the samples below.
Sidebar: select Profile
Profile → Account. Click Tenant ID to copy. Values below are dummy examples.

2. Allowlist your website origin

  1. An Admin opens Settings → Origin and adds your public site origin, for example https://www.yourcompany.com (scheme + host, no path).
  2. If those leads should belong to a team, add the same origin on that team’s Source origins in User Management → Teams. Team origins win when both match.
  3. Call the API from that origin. Browsers send Origin automatically. Server-side callers should set it themselves.
Teams: New Team or Edit Team → Source origins. Dummy value shown.
Settings → Origin. Dummy origin shown. Use Add Origin for tenant-wide capture.

3. Request body

Send a JSON object. Provide either a vehicle (make, model, year) or an “other” package (other.type, other.name). Do not send both.

FieldRequiredNotes
make, model, yearOne of the two shapesVehicle package. year is an integer from 1900 to 2100.
other.type, other.nameOne of the two shapesNon-vehicle freight. Optional weight, dimensions, description.
contactEmailRecommendedValid email. Contact name and company are derived from it when you omit those fields.
contactPhoneOptionalShipper phone.
originCity / originState / originZipOptionalPickup location.
destinationCity / destinationState / destinationZipOptionalDelivery location.
transportTypeOptionalExamples: Open, Enclosed, Flat bed, Dry van.
source, notes, extra fieldsOptionalUnknown fields are stored with the lead as capture extras. They are not dropped.

4. Request samples

curl --location --request POST "__CAPTURE_URL__" \
  --header "Content-Type: application/json" \
  --header "Origin: https://www.yourcompany.com" \
  --header "x-tenant-id: YOUR_TENANT_ID" \
  --data-raw '{
    "make": "Honda",
    "model": "Civic",
    "year": 2018,
    "source": "website",
    "contactEmail": "jane@example.com",
    "contactPhone": "+1-555-111-2222",
    "originCity": "Columbus",
    "originState": "OH",
    "originZip": "43004",
    "destinationCity": "Cleveland",
    "destinationState": "OH",
    "destinationZip": "44101",
    "transportType": "Open"
  }'
$payload = [
    "make" => "Honda",
    "model" => "Civic",
    "year" => 2018,
    "source" => "website",
    "contactEmail" => "jane@example.com",
    "contactPhone" => "+1-555-111-2222",
    "originCity" => "Columbus",
    "originState" => "OH",
    "originZip" => "43004",
    "destinationCity" => "Cleveland",
    "destinationState" => "OH",
    "destinationZip" => "44101",
    "transportType" => "Open",
];

$ch = curl_init("__CAPTURE_URL__");
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        "Content-Type: application/json",
        "Origin: https://www.yourcompany.com",
        "x-tenant-id: YOUR_TENANT_ID",
    ],
    CURLOPT_POSTFIELDS => json_encode($payload),
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
use Illuminate\Support\Facades\Http;

$payload = [
    "make" => "Honda",
    "model" => "Civic",
    "year" => 2018,
    "source" => "website",
    "contactEmail" => "jane@example.com",
    "contactPhone" => "+1-555-111-2222",
    "originCity" => "Columbus",
    "originState" => "OH",
    "originZip" => "43004",
    "destinationCity" => "Cleveland",
    "destinationState" => "OH",
    "destinationZip" => "44101",
    "transportType" => "Open",
];

$response = Http::withHeaders([
    "Origin" => "https://www.yourcompany.com",
    "x-tenant-id" => "YOUR_TENANT_ID",
])->post("__CAPTURE_URL__", $payload);

$status = $response->status();
$data = $response->json();
const response = await fetch("__CAPTURE_URL__", {
    method: "POST",
    headers: {
        "Content-Type": "application/json",
        "Origin": "https://www.yourcompany.com",
        "x-tenant-id": "YOUR_TENANT_ID",
    },
    body: JSON.stringify({
        make: "Honda",
        model: "Civic",
        year: 2018,
        source: "website",
        contactEmail: "jane@example.com",
        contactPhone: "+1-555-111-2222",
        originCity: "Columbus",
        originState: "OH",
        originZip: "43004",
        destinationCity: "Cleveland",
        destinationState: "OH",
        destinationZip: "44101",
        transportType: "Open",
    }),
});
const data = await response.json();
import requests

payload = {
    "make": "Honda",
    "model": "Civic",
    "year": 2018,
    "source": "website",
    "contactEmail": "jane@example.com",
    "contactPhone": "+1-555-111-2222",
    "originCity": "Columbus",
    "originState": "OH",
    "originZip": "43004",
    "destinationCity": "Cleveland",
    "destinationState": "OH",
    "destinationZip": "44101",
    "transportType": "Open",
}
headers = {
    "Content-Type": "application/json",
    "Origin": "https://www.yourcompany.com",
    "x-tenant-id": "YOUR_TENANT_ID",
}
response = requests.post("__CAPTURE_URL__", json=payload, headers=headers)
print(response.status_code, response.json())
package main

import (
    "bytes"
    "encoding/json"
    "net/http"
)

func main() {
    body, _ := json.Marshal(map[string]any{
        "make":             "Honda",
        "model":            "Civic",
        "year":             2018,
        "source":           "website",
        "contactEmail":     "jane@example.com",
        "contactPhone":     "+1-555-111-2222",
        "originCity":       "Columbus",
        "originState":      "OH",
        "originZip":        "43004",
        "destinationCity":  "Cleveland",
        "destinationState": "OH",
        "destinationZip":   "44101",
        "transportType":    "Open",
    })
    req, _ := http.NewRequest(http.MethodPost, "__CAPTURE_URL__", bytes.NewReader(body))
    req.Header.Set("Content-Type", "application/json")
    req.Header.Set("Origin", "https://www.yourcompany.com")
    req.Header.Set("x-tenant-id", "YOUR_TENANT_ID")
    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        panic(err)
    }
                defer resp.Body.Close()
}
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;

var payload = new {
    make = "Honda",
    model = "Civic",
    year = 2018,
    source = "website",
    contactEmail = "jane@example.com",
    contactPhone = "+1-555-111-2222",
    originCity = "Columbus",
    originState = "OH",
    originZip = "43004",
    destinationCity = "Cleveland",
    destinationState = "OH",
    destinationZip = "44101",
    transportType = "Open",
};

using var client = new HttpClient();
using var request = new HttpRequestMessage(HttpMethod.Post, "__CAPTURE_URL__");
request.Headers.TryAddWithoutValidation("Origin", "https://www.yourcompany.com");
request.Headers.TryAddWithoutValidation("x-tenant-id", "YOUR_TENANT_ID");
request.Content = new StringContent(JsonSerializer.Serialize(payload), Encoding.UTF8);
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");

using var response = await client.SendAsync(request);
var body = await response.Content.ReadAsStringAsync();
Console.WriteLine((int)response.StatusCode);
Console.WriteLine(body);
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

String json = """
    {
      "make": "Honda",
      "model": "Civic",
      "year": 2018,
      "source": "website",
      "contactEmail": "jane@example.com",
      "contactPhone": "+1-555-111-2222",
      "originCity": "Columbus",
      "originState": "OH",
      "originZip": "43004",
      "destinationCity": "Cleveland",
      "destinationState": "OH",
      "destinationZip": "44101",
      "transportType": "Open"
    }
    """;

HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("__CAPTURE_URL__"))
    .header("Content-Type", "application/json")
    .header("Origin", "https://www.yourcompany.com")
    .header("x-tenant-id", "YOUR_TENANT_ID")
    .POST(HttpRequest.BodyPublishers.ofString(json))
    .build();

HttpResponse response = HttpClient.newHttpClient()
    .send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode());
System.out.println(response.body());
import java.net.URI
import java.net.http.HttpClient
import java.net.http.HttpRequest
import java.net.http.HttpResponse

val json = """
    {
      "make": "Honda",
      "model": "Civic",
      "year": 2018,
      "source": "website",
      "contactEmail": "jane@example.com",
      "contactPhone": "+1-555-111-2222",
      "originCity": "Columbus",
      "originState": "OH",
      "originZip": "43004",
      "destinationCity": "Cleveland",
      "destinationState": "OH",
      "destinationZip": "44101",
      "transportType": "Open"
    }
""".trimIndent()

val request = HttpRequest.newBuilder()
    .uri(URI.create("__CAPTURE_URL__"))
    .header("Content-Type", "application/json")
    .header("Origin", "https://www.yourcompany.com")
    .header("x-tenant-id", "YOUR_TENANT_ID")
    .POST(HttpRequest.BodyPublishers.ofString(json))
    .build()

val response = HttpClient.newHttpClient()
    .send(request, HttpResponse.BodyHandlers.ofString())
println(response.statusCode())
println(response.body())
require "json"
require "net/http"
require "uri"

uri = URI.parse("__CAPTURE_URL__")
payload = {
  make: "Honda",
  model: "Civic",
  year: 2018,
  source: "website",
  contactEmail: "jane@example.com",
  contactPhone: "+1-555-111-2222",
  originCity: "Columbus",
  originState: "OH",
  originZip: "43004",
  destinationCity: "Cleveland",
  destinationState: "OH",
  destinationZip: "44101",
  transportType: "Open",
}

request = Net::HTTP::Post.new(uri)
request["Content-Type"] = "application/json"
request["Origin"] = "https://www.yourcompany.com"
request["x-tenant-id"] = "YOUR_TENANT_ID"
request.body = JSON.generate(payload)

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") do |http|
  http.request(request)
end
puts response.code
puts response.body
$payload = @{
    make = "Honda"
    model = "Civic"
    year = 2018
    source = "website"
    contactEmail = "jane@example.com"
    contactPhone = "+1-555-111-2222"
    originCity = "Columbus"
    originState = "OH"
    originZip = "43004"
    destinationCity = "Cleveland"
    destinationState = "OH"
    destinationZip = "44101"
    transportType = "Open"
}

$response = Invoke-RestMethod `
    -Method Post `
    -Uri "__CAPTURE_URL__" `
    -ContentType "application/json" `
    -Headers @{
        Origin = "https://www.yourcompany.com"
        "x-tenant-id" = "YOUR_TENANT_ID"
    } `
    -Body ($payload | ConvertTo-Json)

$response | ConvertTo-Json -Depth 6
fetch("__CAPTURE_URL__", {
    method: "POST",
    headers: {
        "Content-Type": "application/json",
        "x-tenant-id": "YOUR_TENANT_ID"
        // Origin is set by the browser to this page's origin.
    },
    body: JSON.stringify({
        make: "Honda",
        model: "Civic",
        year: 2018,
        source: "website",
        contactEmail: "jane@example.com",
        contactPhone: "+1-555-111-2222",
        originCity: "Columbus",
        originState: "OH",
        originZip: "43004",
        destinationCity: "Cleveland",
        destinationState: "OH",
        destinationZip: "44101",
        transportType: "Open"
    })
})
    .then(function (res) { return res.json().then(function (body) { return { status: res.status, body: body }; }); })
    .then(function (result) { console.log(result.status, result.body); });
$.ajax({
    url: "__CAPTURE_URL__",
    method: "POST",
    contentType: "application/json",
    headers: {
        "x-tenant-id": "YOUR_TENANT_ID"
    },
    data: JSON.stringify({
        make: "Honda",
        model: "Civic",
        year: 2018,
        source: "website",
        contactEmail: "jane@example.com",
        contactPhone: "+1-555-111-2222",
        originCity: "Columbus",
        originState: "OH",
        originZip: "43004",
        destinationCity: "Cleveland",
        destinationState: "OH",
        destinationZip: "44101",
        transportType: "Open"
    }),
    success: function (data, _text, xhr) {
        console.log(xhr.status, data);
    },
    error: function (xhr) {
        console.log(xhr.status, xhr.responseJSON);
    }
});

5. Expected responses

{
  "ok": true,
  "status": 201,
  "invokedMethod": "Public Lead Capture",
  "timestamp": "2026-08-14T10:15:30.000Z",
  "data": {
    "id": "8f1c2a3b-4d5e-6789-abcd-ef0123456789",
    "contactEmail": "jane@example.com",
    "originCity": "Columbus",
    "destinationCity": "Cleveland",
    "captureOrigin": "https://www.yourcompany.com",
    "teamId": null
  }
}
{
  "ok": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Provide either vehicle (make, model, year) or other (type, name)",
    "requestId": "uuid"
  }
}
{
  "ok": false,
  "error": {
    "code": "BAD_REQUEST",
    "message": "Tenant context required for lead capture",
    "requestId": "uuid"
  }
}
{
  "ok": false,
  "error": {
    "code": "FORBIDDEN",
    "message": "Origin is not allowed for lead capture (tenant: YOUR_TENANT_ID, origin: https://unknown.example)",
    "requestId": "uuid"
  }
}
{
  "ok": false,
  "error": {
    "code": "TOO_MANY_REQUESTS",
    "message": "Rate limit exceeded, retry in 1 minute",
    "requestId": "uuid"
  }
}

6. Integration notes