Car Image API

مشتریان · ابزارهای نمایندگی، واردات و VIN

چگونه در نرم‌افزار نمایندگی، یک VIN یا فهرست موجودی را به عکسی برای هر خودرو تبدیل کنیم

چگونه ابزارهای نمایندگی و واردات از یک VIN یا یک سطر برگهٔ موجودی به یک تصویر استودیویی روی هر رکورد می‌رسند: رمزگشایی رایگان VIN، resolve، شناسه‌های پایدار و URLهای امضاشده.

مشکل: رکورد ماه‌ها پیش از داشتن عکس، VIN دارد

یک رکورد موجودی در CRM، ERP یا سیستم مدیریت نمایندگی (DMS) با یک VIN، یک شمارهٔ موجودی و یک قیمت شروع می‌شود. عکس زمانی می‌رسد که عکاس به محوطهٔ نمایندگی بیاید، و برای برخی خودروها هرگز نمی‌رسد: خودرویی که در حال حمل است، خودروی تعویضی که هنوز در حال بازسازی است، خودروی وارداتی که نام مدلش با هیچ موردی در فید تصاویر DMS مطابقت ندارد، یا خودرویی از دههٔ ۱۹۹۰ که هیچ‌کس مجوز عکس رسمی‌اش را نگرفته است. هر صفحه‌ای که آن رکورد را نشان می‌دهد، از فهرست فروشنده و ارزیابی کارشناس خرید تا پیش‌فاکتور مشتری، به‌جای عکس یک جای خالی خاکستری نمایش می‌دهد.

ابزارهای نمایندگی و واردات که روی این API کار می‌کنند، آن جای خالی را با اطلاعاتی که رکورد از قبل دارد پر می‌کنند. اگر VIN داشته باشد، تصویر فقط یک رمزگشایی رایگان فاصله دارد. اگر فقط یک خط در فهرست موجودی داشته باشد، resolve متنی کار را انجام می‌دهد. در هر صورت، رکورد در نهایت یک شناسه خودروی پایدار خواهد داشت و همه صفحه‌ها همان خودرو را به همان شکل نمایش می‌دهند.

یکپارچه‌سازی برای نمایندگی‌ها چگونه است

  • رمزگشایی هنگام ثبت. VIN یک بار، هنگام ایجاد رکورد، رمزگشایی می‌شود و شناسهٔ خودرو در کاتالوگ کنار آن ذخیره می‌شود. هیچ بخشی در مراحل بعدی نام سازنده یا مدل را تایپ نمی‌کند.
  • یک نما برای فهرست، یک نما برای صفحهٔ جزئیات. نمای مستقیم side در کادری عریض برای فهرست‌های موجودی؛ front-3-4 برای صفحهٔ جزئیات و پیش‌فاکتور.
  • سال‌های قدیمی. موجودی وارداتی و کارکرده تا دههٔ ۱۹۹۰ عقب می‌رود و درست مانند خودروهای تازه‌رسیده رندر می‌شود: کاتالوگ از 1990 تا سال مدل جاری را پوشش می‌دهد، از جمله مدل‌های بازار داخلی ژاپن.
  • URLهای امضاشده درون برنامه. CRM یک مرورگر است، پس URLهای امضاشده و بدون کلیدی را بارگذاری می‌کند که سرور ایجاد کرده است، تا پنجاه عدد در هر فراخوانی، و برای رکوردهایی که بیش از یک هفته باقی می‌مانند آن‌ها را تمدید می‌کند.

گام ۱: رمزگشایی رایگان VIN

GET /api/v1/vin/{vin} هزینه‌ای ندارد و فقط به یک API key نیاز دارد. این مسیر سال، سازنده، مدل، تریم، نوع بدنه، موتور و هر ویژگی دیگری را که داده‌های vPIC سازمان NHTSA در اختیار دارد، به‌صورت رمزگشایی‌شده برمی‌گرداند، و اگر خودرو در کاتالوگ موجود باشد، یک شیء vehicle با شناسه پایدار و یک image_path آماده نیز برمی‌گرداند. VINهای ناقص هم پشتیبانی می‌شوند: دست‌کم پنج نویسه، * به‌جای هر موقعیت نامعلوم، به‌علاوه راهنمای اختیاری year.

رمزگشایی
curl -s -H "Authorization: Bearer $CAR_IMAGE_API_KEY" \
  "https://carimage.dev/api/v1/vin/1HGCM82633A004352"
200 OK (خلاصه‌شده)
{
  "data": {
    "vin": "1HGCM82633A004352",
    "valid": true,
    "year": 2003,
    "make": "Honda",
    "model": "Accord",
    "trim": "EX-V6",
    "body_class": "Coupe",
    "vehicle": {
      "id": "veh_3qfyk22gfhsx3",
      "make": "Honda",
      "model": "Accord",
      "year": 2003,
      "image_path": "/api/v1/images/car?vehicle=veh_3qfyk22gfhsx3"
    }
  },
  "request_id": "req_01j9x…"
}

گام ۱ب: وقتی تنها چیزی که در اختیار دارید یک سطر در فهرست موجودی است

خودروهای وارداتی اغلب به‌صورت یک صفحه‌گسترده می‌رسند: سال، سازنده، نام مدل با هر املایی که حراجی به کار برده، و یک کد درجه یا تیپ. POST /api/v1/images/resolve رایگان و قطعی است: واژه‌های مربوط به سال، رنگ و نما را از عبارت جدا می‌کند، با باقی‌ماندهٔ آن در کاتالوگ جست‌وجو می‌کند و پارامترهای دقیق را همراه با میزان اطمینانی برمی‌گرداند که می‌توانید بر اساس آن تصمیم بگیرید.

شناسایی خودروی یک ردیف از برگهٔ موجودی
curl -s -X POST https://carimage.dev/api/v1/images/resolve \
  -H "Authorization: Bearer $CAR_IMAGE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"query": "2019 toyota voxy zs side"}'
200 OK (خلاصه‌شده)
{
  "data": {
    "params": {
      "vehicle_id": "veh_9w0nvw7jphp6r",
      "make": "toyota",
      "model": "voxy",
      "year": 2019,
      "view": "side",
      "color": "silver"
    },
    "display": {
      "make_name": "TOYOTA",
      "model_name": "VOXY"
    },
    "confidence": "low",
    "image_path": "/api/v1/images/car?make=toyota&model=voxy&year=2019&view=side&color=silver"
  },
  "request_id": "req_01j9x…"
}

خودرو درست است (Toyota Voxy مدل ۲۰۱۹) اما میزان اطمینان low است، چون «ZS» گریدی است که کاتالوگ آن را نمی‌شناسد و تطبیق باید بدون در نظر گرفتن آن انجام می‌شد. در وارد کردن دسته‌ای، high را تمام‌شده در نظر بگیرید و medium و low را همراه با فهرست candidates برای بررسی به یک انسان بسپارید. وقتی فهرست از قبل سال و سازنده را در ستون‌های جداگانه دارد، آن‌ها را در فیلدهای year و make بفرستید و فقط مدل را در query بگذارید؛ تطبیق بسیار دقیق‌تر می‌شود. عبارتی بدون هیچ واژهٔ مرتبط با خودرو خطای 400 می‌دهد، و سازنده‌ای بدون مدل منطبق، خطای 404 می‌دهد که سال‌های آن سازنده را فهرست می‌کند تا بتوانید مدل را بپرسید.

گام ۲: شناسهٔ خودرو را در رکورد نگه دارید

از هر مسیری که به اینجا رسیدید، vehicle.id (یا params.vehicle_id) را به‌صورت یک ستون رشته‌ای ساده در رکورد موجودی ذخیره کنید. این شناسه قطعی و دائمی است: یک خودرو در هر استقرار و پس از هر انتشار کاتالوگ همان شناسه را دارد، بنابراین استفاده از آن به‌عنوان کلید خارجی امن است. از آن پس هر درخواست تصویر به شکل vehicle=veh_… است که امکان غلط املایی ندارد، و اگر سازنده‌ای نام برندی را تغییر دهد یا منبعی آن را دوباره دسته‌بندی کند، هیچ URL ذخیره‌شده‌ای از کار نمی‌افتد.

گام ۳: یک نما برای فهرست، یک نما برای صفحهٔ جزئیات

فهرست‌های موجودی پهن و کوتاه هستند، بنابراین نمای جانبی مستقیم در کادری ۲:۱ انتخاب معمول است: همهٔ خودروها به یک سمت رو دارند و روی یک خط پایه قرار می‌گیرند. trim=1&padding=6 پیش از جای‌گذاری، تصویر را به اندازهٔ خودرو برش می‌دهد، بنابراین یک Hilux و یک Yaris ردیف را به یک شکل پر می‌کنند؛ fit=contain بوم را دقیقاً ۶۴۰×۳۲۰ با حاشیه‌های شفاف نگه می‌دارد. صفحهٔ جزئیات از front-3-4 با اندازهٔ ۱۰۲۴ استفاده می‌کند و این دو یک کش مشترک دارند: رنگی که مشخص نکرده باشید در هر دو نقره‌ای است.

تصویر فهرست برای یک رکورد
curl --fail-with-body -H "Authorization: Bearer $CAR_IMAGE_API_KEY" \
  "https://carimage.dev/api/v1/images/car?vehicle=veh_3qfyk22gfhsx3&view=side&w=640&h=320&fit=contain&trim=1&padding=6&format=webp" \
  -o stock-4471.webp

گام ۴: نمایش آن در CRM از طریق URLهای امضاشده

CRM در مرورگر اجرا می‌شود و مرورگر هرگز نباید کلید API را در اختیار داشته باشد. وقتی صفحه‌ای فهرستی از موجودی را نشان می‌دهد، سرور با POST /api/v1/image-urls برای هر رکورد یک URL امضاشده می‌سازد (حداکثر پنجاه عدد در هر فراخوانی؛ تصویر هر URL به‌عنوان یک تصویر خودروی ماه محاسبه می‌شود) و صفحه آن‌ها را مانند هر تصویر دیگری بارگذاری می‌کند. برای رکوردی که ماه‌ها در موجودی می‌ماند، دو تنظیم اهمیت دارد:

  • ttl_seconds: 604800 همراه با renew: true: URL پس از TTL هفت‌روزه همچنان کار می‌کند و هر تمدید، تصویر را یک بار در ماهی که در آن رخ می‌دهد می‌شمارد و اگر در آن ماه قبلاً شمرده شده باشد، چیزی اضافه نمی‌شود. ماه‌هایی که کسی خودرو را نبیند، چیزی شمرده نمی‌شود.
  • یک Idempotency-Key برای هر صفحه از همگام‌سازی: درخواستی که دوباره ارسال شود همان پاسخ اول را برمی‌گرداند و هیچ چیزی دو بار ایجاد نمی‌شود.

کلید صادرکننده را در داشبورد به مبدأ (origin) CRM محدود کنید تا URLی که به سایت دیگری نشت کند، پاسخ 403 بگیرد. باطل کردن کلید، همهٔ URLهایی را که صادر کرده نامعتبر می‌کند. اگر تصاویر خودروی ماهانهٔ طرح تمام شده باشد، تمدید پاسخ 402 می‌گیرد و همان URL پس از بازنشانی سهمیه یا ارتقای طرح دوباره کار می‌کند. چرخهٔ کامل در مستندات URL امضاشده آمده است.

پذیرش خودرو و فهرست موجودی، با TypeScript SDK
import { CarImageClient } from "@meterapp/car-image-sdk";

const client = new CarImageClient({ apiKey: process.env.CAR_IMAGE_API_KEY });

// On intake: VIN in, vehicle id on the record. Free.
const { data: decoded } = await client.decodeVin(stock.vin);
if (decoded.vehicle) {
  stock.vehicleId = decoded.vehicle.id; // veh_…, permanent; the record never spells a car again
  stock.trim = decoded.trim;            // shown next to the image, never claimed by it
}

// When the CRM draws the stock list: one signed URL per record, up to fifty per call.
// The browser loads them; the key never leaves the server.
const { data: urls } = await client.createImageUrls(
  page.map((row) => ({
    vehicle: row.vehicleId, view: "side",
    width: 640, height: 320, fit: "contain", trim: true, padding: 6, format: "auto",
  })),
  { ttlSeconds: 604_800, renew: true, renewDays: 365, idempotencyKey: `stock-list:${syncRunId}:${pageIndex}` }
);

CLI، SDK و MCP

npx @meterapp/car-image
# decode for free; the output names the vehicle id and a ready-to-run image command
npx @meterapp/car-image vin 1HGCM82633A004352
npx @meterapp/car-image vin 1HGCM82633A004352 --json | jq -r .data.vehicle.id

# a partial VIN from a faded door sticker: at least five characters, * for each unknown position
npx @meterapp/car-image vin "1HGCM826*3A" --year 2003

# the list image for one record
npx @meterapp/car-image get --vehicle veh_3qfyk22gfhsx3 --view side --width 640 --height 320 --fit contain --trim --padding 6 --format webp --out stock-4471.webp
  • SDK: client.decodeVin(vin, { year? })، client.resolve(query)، client.getImage({ vehicle, … }) و client.createImageUrls(…)، مانند نمونه بالا.
  • MCP: decode_vin، resolve_vehicle، get_car_image و create_car_image_urls در مجموعه‌ابزار اصلی هستند، بنابراین دستیاری که سیستم موجودی را در اختیار دارد می‌تواند از روی VIN ثبت‌شده در رکورد به درخواست «عکس خودروی شمارهٔ ۴۴۷۱ موجودی» پاسخ دهد. راه‌اندازی در صفحهٔ MCP آمده است؛ فیلدها و خطاهای رمزگشا در مستندات VIN هستند.

پرسش‌های متداول

قرار دادن عکس روی همهٔ رکوردهای موجودی چقدر هزینه دارد؟
رمزگشایی VIN رایگان است. هر خودرو در هر رنگ و نما یک تصویر خودرو است و صرف‌نظر از دفعات نمایش و در هر اندازه‌ای، ماهی یک بار حساب می‌شود؛ بررسی مجدد آن با If-None-Match رایگان است. URL امضاشده تصویرش را هنگام ساخته‌شدن حساب می‌کند و با renew: true، در هر ماه بعدی که باز شود یک بار دیگر. یک گروه نمایندگی با چند هزار خودرو در موجودی، ماهانه چند هزار تصویر خودرو نمایش می‌دهد، پس پلن را متناسب با موجودی در حال نمایش انتخاب کنید.
VIN رمزگشایی می‌شود اما vehicle برابر null است. حالا چه کنم؟
رمزگشا برند، مدل و سال را تشخیص داده، اما کاتالوگ برای این ترکیب ورودی ندارد: مثلاً یک تریلر، برخی شاسی‌های تجاری، یا نام مدلی که منابع هنوز ثبت نکرده‌اند. فیلدهای رمزگشایی‌شده را نمایش دهید، کاتالوگ را با GET /api/v1/vehicles?q= جست‌وجو کنید، شاید املا متفاوت باشد، و خودرو را در صفحهٔ درخواست‌ها درخواست کنید. POST /api/v1/requests به‌جای ایجاد درخواست تکراری، به درخواست باز موجود رأی می‌دهد.
آیا رمزگشایی VIN خودروهای وارداتی و خودروهایی را که هرگز در آمریکا فروخته نشده‌اند پوشش می‌دهد؟
رمزگشا از داده‌های vPIC سازمان NHTSA استفاده می‌کند، بنابراین VIN خودروی سازنده‌ای که اطلاعات خود را در NHTSA ثبت می‌کند به‌طور کامل رمزگشایی می‌شود. خودرویی که هرگز برای آمریکا تأییدیه نگرفته، اغلب فقط به سازنده و سال، بدون مدل، رمزگشایی می‌شود و برخی اصلاً رمزگشایی نمی‌شوند. برای چنین موجودی‌ای، به‌جای آن از روی سند ثبت خودرو شناسایی کنید: خودِ کاتالوگ جهانی است و از سال 1990 را پوشش می‌دهد، و مدل‌های بازار داخلی ژاپن مانند Toyota Voxy نیز در آن هستند.
آیا رندر، تریم ثبت‌شده در رکورد را نشان می‌دهد؟
خیر. کاتالوگ بر اساس سازنده، مدل و سال کلیدگذاری شده است، بنابراین یک کوپهٔ EX-V6 و یک سدان LX هر دو به‌صورت همان Accord مدل 2003 رندر می‌شوند. trim و body_class حاصل از رمزگشایی را به‌صورت متن در کنار تصویر نگه دارید و هرگز رندر را به‌عنوان همان خودروی مشخص معرفی نکنید.
آیا وب‌سایت نمایندگی می‌تواند از همان URLهای CRM استفاده کند؟
آن‌ها را با کلیدی بسازید که وب‌سایت در فهرست مبداهای مجاز آن باشد؛ در این صورت اگر مرورگری URL را از هر سایت دیگری بارگذاری کند، پاسخ 403 origin_not_allowed دریافت می‌کند. بارگذاری‌های بدون Referer، مانند کلاینت ایمیل، مجاز هستند. CRM و وب‌سایت می‌توانند از یک کلید و یک مجموعه URL مشترک استفاده کنند، یا هر کدام کلید جداگانه‌ای داشته باشند تا بتوان هر یک را به‌تنهایی باطل کرد.