Embed the widget
Paste this where the quote form should appear. Use your own partner key.
<div id="atv-quote-widget" data-widget-key="YOUR_WIDGET_KEY"></div>
<script async src="https://www.autotransportvehicle.com/embed/v1/widget.js"></script>For several widgets on one page, use data-atv-widget instead of the id. Older snippets that load https://autotransportvehicle.com/embed/widget.js keep working.
Formats
One script, four shapes. Set data-mode on the host; every format quotes through the same engine and hands off to the same booking page. Launchers open the full quote form in an accessible dialog (focus is trapped, Escape closes it, and focus returns to the launcher).
| data-mode | What renders | Best for |
|---|---|---|
form (default) | The full instant-quote form inline | Vehicle detail pages, checkout |
strip | A one-line delivery-ZIP box; prices in a dialog with the host prefill | Under the sticker price |
button | A call-to-action button that opens the form in a dialog | Search result cards, sidebars |
badge | A pinned badge that opens the dialog; data-position is bottom-right (default), bottom-left or inline | Site-wide, dealer groups |
<!-- Search results card: one button per vehicle -->
<div data-atv-widget
data-widget-key="YOUR_WIDGET_KEY"
data-mode="button"
data-label="Ship this one"
data-origin-zip="84070"
data-vehicle-year="2026" data-vehicle-make="Toyota" data-vehicle-model="Tacoma"
data-vehicle-type="pickup"></div>With the strip, give the dealer's lot ZIP in data-origin-zip and, ideally, data-ship-date: when the dialog already has pickup ZIP, delivery ZIP and a date, it prices immediately after the shopper enters their ZIP.
Brand match
Three optional attributes match the widget to your site. A widget without them renders exactly as before. Changing them after the widget has mounted re-themes it in place.
<div id="atv-quote-widget"
data-widget-key="YOUR_WIDGET_KEY"
data-accent="#B42318"
data-theme="light"
data-radius="6"></div>data-accent is a hex color. data-theme is light or dark. data-radius is the corner radius in pixels, 0 to 32.
Text on the accent color switches between white and near-black for contrast, and links and focus rings fall back to the theme's text color when the brand color is too light to read. For finer control, set the CSS custom properties directly on the host element from your own stylesheet:
#atv-quote-widget {
--atv-accent: #B42318;
--atv-on-accent: #fff;
--atv-radius: 6px;
--atv-font: "Your Brand Sans", system-ui, sans-serif;
}Prefill from your page (optional)
If your page already knows the vehicle or where it is (an auction lot, a dealer listing), pass it on the host element so the buyer only enters a delivery ZIP. Every attribute is optional, is checked before use, and stays editable by the buyer. Invalid values are ignored.
<div id="atv-quote-widget"
data-widget-key="YOUR_WIDGET_KEY"
data-origin-zip="89101"
data-dest-zip="33101"
data-vehicle-year="2019"
data-vehicle-make="Toyota"
data-vehicle-model="Camry"
data-vin="4T1B11HK7KU123456"
data-vehicle-type="sedan"
data-transport-type="open"
data-ship-date="2027-01-15"></div>data-vehicle-type is one of sedan, suv, pickup, van, motorcycle, inoperable, oversize. data-transport-type is open or enclosed. data-ship-date is YYYY-MM-DD (today or later) or +N for N days from today, up to 180. Year, make, model and VIN carry through to the booking page.
React, Next.js and single-page apps
The script mounts any host that appears later, including after client-side navigation, and mounting the same element twice does nothing. To control mounting yourself, call window.ATVWidget.mount(el).
// Next.js (App Router)
'use client'
import Script from 'next/script'
export function ShippingQuote() {
return (
<>
<div data-atv-widget="" data-widget-key={process.env.NEXT_PUBLIC_ATV_WIDGET_KEY} />
<Script src="https://www.autotransportvehicle.com/embed/v1/widget.js" strategy="afterInteractive" />
</>
)
}Events
The host element dispatches DOM events that bubble. They never contain customer personal data.
document.addEventListener('atv:quote', (e) => {
// e.detail = { quote_id, customer_price, program, expires_at }
})
document.addEventListener('atv:book_click', (e) => { /* { quote_id } */ })
document.addEventListener('atv:error', (e) => { /* { stage, error_code } */ })Booking happens on autotransportvehicle.com in a new tab, so card and contact details never pass through your page.
Approved origins
Each key works only on the exact origins listed on your partner account, such as https://www.yourdealer.com. A request from any other site gets 403 origin_not_allowed and no price, and the attempt shows up in your dashboard. Server-to-server calls without an Origin header are accepted. Keep your key on your servers if you use the API that way.
Quote API
POST https://www.autotransportvehicle.com/api/widget/quote
Content-Type: application/json
{
"widget_key": "YOUR_WIDGET_KEY",
"origin_zip": "89101", // 5-digit US ZIP
"dest_zip": "33101",
"vehicle_type": "suv", // sedan | suv | pickup | van | motorcycle | inoperable | oversize
"transport_type": "open", // open | enclosed
"ship_date": "2026-11-02", // YYYY-MM-DD, today or later
"session_id": "any-stable-id" // groups events for attribution
}
200 OK
{
"quote_id": "uuid",
"customer_price": 1050, // USD, all-in price shown to the customer
"eta_window_days": { "min": 3, "max": 6 }, // transit estimate, not a guarantee
"expires_at": "2026-10-12T16:00:00Z", // price valid until
"program": "standard", // standard | snowbird
"sandbox": false
}
Booking page for a quote: https://www.autotransportvehicle.com/book/{quote_id}Errors
{ "error_code": "origin_not_allowed", "message": "…", "retryable": false, "field_errors": { … } }| HTTP | error_code | Meaning |
|---|---|---|
| 400 | validation_failed | Body invalid; see field_errors |
| 403 | invalid_widget_key | Unknown key |
| 403 | partner_inactive | Partner not active (pending, paused or terminated) |
| 403 | origin_not_allowed | Calling site is not an approved origin for this key |
| 429 | rate_limited | Too many requests; retry after a minute |
| 4xx | upstream code | The fulfillment partner rejected the route or inputs |
| 502 | fulfillment_unreachable | Pricing is temporarily unavailable; retryable |
Rate limits
Limits are per client IP: 30 quotes per minute, 60 events per minute and 5 booking submissions per minute. They are enforced per server instance, so treat them as minimums, not guarantees.
Sandbox
This key returns real prices, but bookings are simulated (reference SANDBOX-…), nothing is sent to the fulfillment partner, and no commission accrues. It is authorized on http://localhost:3000 and http://localhost:4173.
<div id="atv-quote-widget" data-widget-key="atv_sandbox_57cd79389c6b3ab6669990b8"></div>
<script async src="https://www.autotransportvehicle.com/embed/v1/widget.js"></script>Content Security Policy
script-src https://www.autotransportvehicle.com;
connect-src https://www.autotransportvehicle.com https://vpic.nhtsa.dot.gov; # vpic = optional VIN autofillThe widget renders in a shadow root with its own styles, uses no cookies, and stores one random session id in localStorage for 30 days. It supports current Chrome, Edge, Firefox and Safari.
Versioning and deprecation
/embed/v1/widget.js only receives backward-compatible changes. A breaking change ships as /embed/v2/, and v1 stays served for at least 12 months after v2 is announced. The unversioned /embed/widget.js always serves the latest v1.
Not a partner yet? Apply for a key. Every demo on the homepage is this widget on the sandbox key.