التطبيقات قريبًا
تواصل معنا

التوثيق

LotShow API

Send a lot photo, get a studio photo back. The API runs the same showroom renderer as the web Studio, on the same credit balance, so a photo uploaded in the Studio and a photo posted from your DMS cost the same.

Base URLhttps://api.lotshow.com/v1
FormatJSON over HTTPS
AccessPro and Elite plans

Everything is a job. You post one photo and a backdrop, we return a job id straight away, and about a minute later the finished image is ready. Register a webhook and we call you; or poll the job. The finished photo also lands in the account's Inventory, grouped under the vehicle you named.

Authentication

Create a key in Settings, under API keys. Keys start with ls_live_ and are shown once, so store it somewhere safe. An account can hold up to 10 live keys, and a key stops working if the account drops to the free plan.

Send the key as a bearer token on every request.

Header
Authorization: Bearer ls_live_••••••••••••••••••••••••••••3f9a

Keys carry the full power of the account. Keep them on your server, never in a browser or an app bundle, and revoke any key you think has leaked from the same Settings page.

استدعِ الـ API من خادمك. المتصفحات محظورة: لا يرسل الـ API أي ترويسات CORS، لذا لا تستطيع صفحة ويب استدعاءه، وأي مفتاح داخل صفحة يمكن لأي شخص نسخه.

Quickstart

Check the key first. This returns your balance and plan.

cURL
curl https://api.lotshow.com/v1/credits \
  -H "Authorization: Bearer $LOTSHOW_KEY"
200 OK
{
  "balance": 320,
  "plan": "elite",
  "monthly_credits": 1000,
  "renews": "2026-11-13"
}

Then send a photo. One credit is held for the job.

curl https://api.lotshow.com/v1/jobs \
  -H "Authorization: Bearer $LOTSHOW_KEY" \
  -F image=@stock-4471.jpg \
  -F backdrop=grey-concrete \
  -F vehicle="Stock 4471" \
  -F webhook=https://yourdms.com/hooks/lotshow
202 Accepted
{
  "id": "Hn4kR2pXq8VbT1sLw0Za",
  "status": "queued",
  "backdrop": "grey-concrete",
  "vehicle_id": "pQ7mT2vK9cLx4RbN1sHd",
  "credits_left": 319
}

About a minute later your webhook receives the finished photo. Or fetch the job yourself:

cURL
curl https://api.lotshow.com/v1/jobs/Hn4kR2pXq8VbT1sLw0Za \
  -H "Authorization: Bearer $LOTSHOW_KEY"

When status is completed, output_url is a permanent link to the image. Use it on your listing page.

Photo jobs

A job turns one photo into one studio photo. It moves through four states.

StatusMeaning
queuedAccepted and waiting for a renderer. One credit is held.
processingThe car is being cut out and placed in the backdrop.
completedDone. output_url is set.
failedThe photo could not be finished. The credit goes back and error says why.

Sending the photo

Post it as a multipart image file, or send JSON with an image_url we download for you. JPEG, PNG and WebP are accepted, up to 15 MB. We straighten and shrink the photo to at most 2048 px before it is rendered, the same as the web Studio does. A photo that isn't the whole car seen from outside fails, and its credit comes back.

Grouping by vehicle

Every job belongs to a vehicle in the account's Inventory. Pass vehicle_id to add to an existing one, or a vin or stock number and we find that vehicle, creating it on first use. A vehicle name works the same way. With none of these, photos go into a vehicle called API. Sending several angles of one car with the same VIN keeps them together.

Vehicles

A vehicle is a car in the account's Inventory with its photos, whether it was made through the API or in the web Studio. Key it by VIN or stock number, the same fields the Studio and the feed export use, and your system never has to store our ids.

StatusMeaning
emptyNo photos yet.
processingAt least one photo is queued or processing.
completedEvery photo is finished.
partialEvery photo has finished, and at least one failed.

The shot checklist

shots says which of the eight exterior angles the vehicle's photos cover, read from each photo once it is processed: front, front34_left, side_left, rear34_left, rear, rear34_right, side_right and front34_right. A failed photo covers nothing.

Walkaround order

Photos are listed and sent to your feed round the car: front, front right three quarter, right side, rear right three quarter, rear, rear left three quarter, left side, front left three quarter, then any photo without an angle in the order it was sent.

Feed export

With Feed export set up in Settings, POST /v1/vehicles/{id}/feed uploads the finished photos to your listing feed provider over FTP or SFTP, named by VIN or stock number, the same as the Studio's send button.

DMS sync

Your DMS or inventory tool can run the whole flow on its own, keyed by VIN.

  1. Create the vehicle. POST /v1/vehicles with its vin and stock. This step is optional: the first photo sent with a new VIN creates it too.
  2. Post the photos. One POST /v1/jobs per photo with the same vin. Photos sent in parallel land in the one vehicle.
  3. Receive vehicle.completed. Once every photo has finished, the event carries the vehicle and its finished photos in walkaround order.
  4. Use the photos. Download each output_url into your listing, fetch GET /v1/vehicles/{id}/photos, or call POST /v1/vehicles/{id}/feed to push them to your feed provider.
# 1. The vehicle, keyed by its VIN
curl https://api.lotshow.com/v1/vehicles \
  -H "Authorization: Bearer $LOTSHOW_KEY" \
  -H "Idempotency-Key: create-1HGCV1F34PA004471" \
  -H "Content-Type: application/json" \
  -d '{"vin": "1HGCV1F34PA004471", "stock": "4471"}'

# 2. Each photo, sent with the same VIN
for f in lot/4471/*.jpg; do
  curl https://api.lotshow.com/v1/jobs \
    -H "Authorization: Bearer $LOTSHOW_KEY" \
    -H "Idempotency-Key: $(basename "$f")-1HGCV1F34PA004471" \
    -F image=@"$f" \
    -F vin=1HGCV1F34PA004471
done

Then, when vehicle.completed arrives, push the photos to the feed:

cURL
curl -X POST https://api.lotshow.com/v1/vehicles/pQ7mT2vK9cLx4RbN1sHd/feed \
  -H "Authorization: Bearer $LOTSHOW_KEY" \
  -H "Idempotency-Key: feed-1HGCV1F34PA004471-1"
200 OK
{
  "ok": true,
  "sent": 8
}

To find a vehicle later from your own records, filter by VIN or stock number: GET /v1/vehicles?vin=1HGCV1F34PA004471.

Backdrops

هناك 13 خلفية موزعة على ست صالات عرض: القاعة البيضاء تأتي بثماني نسخ من الجدران والأرضيات، ولكل صالة من الصالات الخمس الأخرى خلفية واحدة. لا يُعاد رسم الطلاء أو الزخارف أو الشعارات أبدًا؛ تُعاد إضاءة السيارة لتناسب القاعة ويتغيّر المشهد حولها. مرّر المعرّف النصي في backdrop. إذا لم تحدده يُستخدم grey-concrete.

SlugName
grey-concreteGrey concrete
white-hallWhite hall
white-tilesWhite tiles
micro-cementMicro-cement
stoneStone
plain-stonePlain stone
dealershipDealership
marble-hallMarble hall
photo-boothPhoto booth
white-studioWhite studio
white-hall-plainWhite hall, plain walls
white-tiles-plainWhite tiles, plain walls
micro-cement-plainMicro-cement, plain walls

Fetch GET /v1/backdrops for a preview image of each.

Webhooks

Webhooks save you polling. There are two ways to receive them, and you can use both.

  • Per job. Pass a webhook URL when you create the job. Only that job's events go there.
  • Per account. Register up to 5 endpoints with POST /v1/webhooks and choose the events each one wants.

Events

EventSent when
job.completedA studio photo is ready.
job.failedA photo could not be finished. The credit is refunded.
vehicle.completedEvery photo of a vehicle has finished and at least one is done. Sent once, and again only after more photos are added. Endpoints only.
credits.lowYour balance drops under 20 credits.

Payloads

Each delivery is a JSON POST with the event name, a timestamp, and the fields below.

job.completed
{
  "event": "job.completed",
  "created_at": "2026-10-14T09:42:14.000Z",
  "id": "Hn4kR2pXq8VbT1sLw0Za",
  "backdrop": "grey-concrete",
  "vehicle_id": "pQ7mT2vK9cLx4RbN1sHd",
  "name": "stock-4471",
  "output_url": "https://firebasestorage.googleapis.com/v0/b/…/default.jpg?alt=media&token=…",
  "seconds": 62,
  "credits_left": 319
}
job.failed
{
  "event": "job.failed",
  "created_at": "2026-10-14T09:42:02.000Z",
  "id": "Hn4kR2pXq8VbT1sLw0Za",
  "backdrop": "grey-concrete",
  "vehicle_id": "pQ7mT2vK9cLx4RbN1sHd",
  "name": "stock-4471",
  "error": "Couldn't finish this photo.",
  "credits_refunded": 1,
  "credits_left": 320
}
vehicle.completed
{
  "event": "vehicle.completed",
  "created_at": "2026-10-14T09:43:10.000Z",
  "vehicle": {
    "id": "pQ7mT2vK9cLx4RbN1sHd",
    "name": "1HGCV1F34PA004471",
    "vin": "1HGCV1F34PA004471",
    "stock": "4471",
    "backdrop": "grey-concrete",
    "photos_total": 8,
    "photos_done": 8,
    "photos_failed": 0,
    "status": "completed",
    "shots": {
      "front": true,
      "front34_left": true,
      "side_left": true,
      "rear34_left": true,
      "rear": true,
      "rear34_right": true,
      "side_right": true,
      "front34_right": true
    },
    "feed": null,
    "created_at": "2026-10-14T09:40:02.000Z",
    "updated_at": "2026-10-14T09:43:10.000Z"
  },
  "photos": [
    {
      "id": "Hn4kR2pXq8VbT1sLw0Za",
      "angle": "front",
      "photo_quality": "good",
      "output_url": "https://firebasestorage.googleapis.com/v0/b/…/default.jpg?alt=media&token=…"
    },
    {
      "id": "Tq9cW3nLx7HbR2kPv5Ms",
      "angle": "front34_right",
      "photo_quality": "good",
      "output_url": "https://firebasestorage.googleapis.com/v0/b/…/default.jpg?alt=media&token=…"
    }
  ]
}
credits.low
{
  "event": "credits.low",
  "created_at": "2026-10-14T09:50:11.000Z",
  "balance": 18,
  "threshold": 20
}

Verifying a delivery

Every delivery is signed with your account's signing secret (it starts with whsec_ and is in Settings, next to your webhook endpoints). We use the Standard Webhooks scheme, so any library for it works. Three headers come with each request:

HeaderValue
webhook-idUnique id of the delivery.
webhook-timestampUnix time in seconds. Reject anything more than five minutes old.
webhook-signaturev1, followed by a base64 HMAC-SHA256 of id.timestamp.body.

Compute the HMAC over the raw request body, not a re-serialised copy.

import { createHmac, timingSafeEqual } from "node:crypto";

export function verify(secret, rawBody, headers) {
  const id = headers["webhook-id"];
  const ts = headers["webhook-timestamp"];
  if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false;

  const key = Buffer.from(secret.replace(/^whsec_/, ""), "base64");
  const expected = createHmac("sha256", key).update(`${id}.${ts}.${rawBody}`).digest();

  return headers["webhook-signature"].split(" ").some((entry) => {
    const [version, sig] = entry.split(",");
    const got = Buffer.from(sig ?? "", "base64");
    return version === "v1" && got.length === expected.length && timingSafeEqual(got, expected);
  });
}

Delivery and retries

Answer with any 2xx within 10 seconds to acknowledge. Anything else counts as a failure and we retry after 1, 5, 15, 60, 180, 360 and 720 minutes, then stop. Recent deliveries and their status codes are listed in Settings.

Credits

The API and the web Studio spend one shared balance. A finished photo costs one credit, whoever asked for it. Credits come from your plan each month and from top-up packs, and both are spendable by the API. See pricing for plans and packs.

A credit is held when a job is accepted. If the job fails, it is returned automatically and credits_charged on the job reads 0. When a request would overdraw the balance it is refused with 402 insufficient_credits.

Jobs

The job object:

FieldTypeDescription
idstringJob id.
statusstringqueued, processing, completed or failed.
backdropstringBackdrop slug.
vehicle_idstringThe Inventory vehicle the photo belongs to.
namestringThe label you sent, or the file name.
output_urlstring or nullPermanent link to the finished photo. Set once completed.
photo_qualitystring or nullgood, soft or poor: how sharp and clean the car in the photo was.
anglestring or nullWhich of the eight exterior shots the photo is, such as front34_left.
errorstring or nullWhy a job failed.
credits_chargedinteger1, or 0 when a failed job was refunded.
secondsinteger or nullTime from request to finished photo.
created_atstringISO 8601 time.
completed_atstring or nullISO 8601 time.

إنشاء مهمة

POST/v1/jobs

Turns one photo into a studio photo. Send a multipart form with an image file, or a JSON body with an image_url. Returns right away; the photo follows by webhook or by polling.

أرسل ترويسة Idempotency-Key لإعادة المحاولة بأمان بعد انتهاء المهلة. طوال 24 ساعة، تحصل إعادة المحاولة بالمفتاح نفسه والمحتوى نفسه على الرد الأول مع Idempotent-Replayed: true، بدلًا من إنشاء مهمة ثانية وصرف نقطة ثانية.

الترويسات

Idempotency-Keystring
أي نص فريد حتى 255 حرفًا، مثل UUID. اختياري.

Parameters

imagefilerequired
The photo, as a multipart file. JPEG, PNG or WebP, up to 15 MB.
image_urlstring
A public http(s) URL we download instead of an upload. Use it in a JSON body.
backdropstring
A backdrop slug. Defaults to grey-concrete.
vehicle_idstring
An existing vehicle to add the photo to. Wins over everything below.
vinstring
The vehicle's VIN, up to 17 letters and digits without I, O or Q. Finds the vehicle, or creates it named after the VIN. Wins over stock and vehicle.
stockstring
The vehicle's stock number, up to 32 characters. Finds the vehicle, or creates it named after the number. Wins over vehicle.
vehiclestring
A vehicle name, up to 80 characters. Created on first use. Defaults to API.
namestring
A label for the photo, up to 120 characters. Defaults to the file name.
webhookstring
A public https URL that receives this job's events.
202 Accepted
{
  "id": "Hn4kR2pXq8VbT1sLw0Za",
  "status": "queued",
  "backdrop": "grey-concrete",
  "vehicle_id": "pQ7mT2vK9cLx4RbN1sHd",
  "credits_left": 319
}

جلب مهمة

GET/v1/jobs/{id}

Returns one job. A job id from another account answers 404 job_not_found.

200 OK
{
  "id": "Hn4kR2pXq8VbT1sLw0Za",
  "status": "completed",
  "backdrop": "grey-concrete",
  "vehicle_id": "pQ7mT2vK9cLx4RbN1sHd",
  "name": "stock-4471",
  "output_url": "https://firebasestorage.googleapis.com/v0/b/…/default.jpg?alt=media&token=…",
  "photo_quality": "good",
  "angle": "front34_left",
  "error": null,
  "credits_charged": 1,
  "seconds": 62,
  "created_at": "2026-10-14T09:41:12.000Z",
  "completed_at": "2026-10-14T09:42:14.000Z"
}

عرض المهام

GET/v1/jobs

Jobs created through the API, newest first. Page with starting_after while has_more is true.

Query parameters

limitinteger
Between 1 and 100. Defaults to 20.
starting_afterstring
A job id. Returns the jobs after it.
200 OK
{
  "data": [
    {
      "id": "Hn4kR2pXq8VbT1sLw0Za",
      "status": "completed",
      "backdrop": "grey-concrete",
      "vehicle_id": "pQ7mT2vK9cLx4RbN1sHd",
      "name": "stock-4471",
      "output_url": "https://firebasestorage.googleapis.com/v0/b/…/default.jpg?alt=media&token=…",
      "photo_quality": "good",
      "angle": "front34_left",
      "error": null,
      "credits_charged": 1,
      "seconds": 62,
      "created_at": "2026-10-14T09:41:12.000Z",
      "completed_at": "2026-10-14T09:42:14.000Z"
    }
  ],
  "has_more": true
}

Vehicles

The vehicle object:

FieldTypeDescription
idstringVehicle id. Jobs carry it as vehicle_id.
namestringThe name shown in Inventory.
vinstring or nullVIN, upper case.
stockstring or nullStock number.
backdropstring or nullThe vehicle's backdrop slug.
photos_totalintegerPhotos on the vehicle.
photos_doneintegerPhotos completed.
photos_failedintegerPhotos that failed.
statusstringempty, processing, completed or partial.
shotsobjectEach of the eight exterior angles, true when a photo covers it.
feedobject or nullThe last feed send: at, ok and count.
created_atstringISO 8601 time.
updated_atstringISO 8601 time.

Create a vehicle

POST/v1/vehicles

Creates an empty vehicle. Send a JSON body. A VIN or stock number another vehicle of the account already has answers 409 vehicle_exists with that vehicle's vehicle_id.

الترويسات

Idempotency-Keystring
أي نص فريد حتى 255 حرفًا، مثل UUID. اختياري.

Parameters

vinstring
Up to 17 letters and digits without I, O or Q. Stored in upper case.
stockstring
Up to 32 characters.
namestring
Up to 80 characters. Defaults to the VIN, else the stock number.
201 Created
{
  "id": "pQ7mT2vK9cLx4RbN1sHd",
  "name": "1HGCV1F34PA004471",
  "vin": "1HGCV1F34PA004471",
  "stock": "4471",
  "backdrop": "grey-concrete",
  "photos_total": 0,
  "photos_done": 0,
  "photos_failed": 0,
  "status": "empty",
  "shots": {
    "front": false,
    "front34_left": false,
    "side_left": false,
    "rear34_left": false,
    "rear": false,
    "rear34_right": false,
    "side_right": false,
    "front34_right": false
  },
  "feed": null,
  "created_at": "2026-10-14T09:40:02.000Z",
  "updated_at": "2026-10-14T09:40:02.000Z"
}

Retrieve a vehicle

GET/v1/vehicles/{id}

Returns one vehicle. A vehicle id from another account answers 404 vehicle_not_found.

200 OK
{
  "id": "pQ7mT2vK9cLx4RbN1sHd",
  "name": "1HGCV1F34PA004471",
  "vin": "1HGCV1F34PA004471",
  "stock": "4471",
  "backdrop": "grey-concrete",
  "photos_total": 8,
  "photos_done": 8,
  "photos_failed": 0,
  "status": "completed",
  "shots": {
    "front": true,
    "front34_left": true,
    "side_left": true,
    "rear34_left": true,
    "rear": true,
    "rear34_right": true,
    "side_right": true,
    "front34_right": true
  },
  "feed": {
    "at": "2026-10-14T09:45:30.000Z",
    "ok": true,
    "count": 8
  },
  "created_at": "2026-10-14T09:40:02.000Z",
  "updated_at": "2026-10-14T09:43:10.000Z"
}

List vehicles

GET/v1/vehicles

Every vehicle on the account, newest first, including those made in the web Studio. Page with starting_after while has_more is true.

Query parameters

vinstring
Only the vehicle with this VIN.
stockstring
Only the vehicle with this stock number.
limitinteger
Between 1 and 100. Defaults to 20.
starting_afterstring
A vehicle id. Returns the vehicles after it.
200 OK
{
  "data": [
    {
      "id": "pQ7mT2vK9cLx4RbN1sHd",
      "name": "1HGCV1F34PA004471",
      "vin": "1HGCV1F34PA004471",
      "stock": "4471",
      "backdrop": "grey-concrete",
      "photos_total": 8,
      "photos_done": 8,
      "photos_failed": 0,
      "status": "completed",
      "shots": {
        "front": true,
        "front34_left": true,
        "side_left": true,
        "rear34_left": true,
        "rear": true,
        "rear34_right": true,
        "side_right": true,
        "front34_right": true
      },
      "feed": {
        "at": "2026-10-14T09:45:30.000Z",
        "ok": true,
        "count": 8
      },
      "created_at": "2026-10-14T09:40:02.000Z",
      "updated_at": "2026-10-14T09:43:10.000Z"
    }
  ],
  "has_more": false
}

Update a vehicle

PATCH/v1/vehicles/{id}

Changes the fields you send and leaves the rest. Send null to clear vin or stock. Vehicles are never deleted through the API.

Parameters

namestring
Up to 80 characters.
vinstring or null
Up to 17 letters and digits without I, O or Q.
stockstring or null
Up to 32 characters.
200 OK
{
  "id": "pQ7mT2vK9cLx4RbN1sHd",
  "name": "1HGCV1F34PA004471",
  "vin": "1HGCV1F34PA004471",
  "stock": "4471",
  "backdrop": "grey-concrete",
  "photos_total": 8,
  "photos_done": 8,
  "photos_failed": 0,
  "status": "completed",
  "shots": {
    "front": true,
    "front34_left": true,
    "side_left": true,
    "rear34_left": true,
    "rear": true,
    "rear34_right": true,
    "side_right": true,
    "front34_right": true
  },
  "feed": {
    "at": "2026-10-14T09:45:30.000Z",
    "ok": true,
    "count": 8
  },
  "created_at": "2026-10-14T09:40:02.000Z",
  "updated_at": "2026-10-14T09:43:10.000Z"
}

List a vehicle's photos

GET/v1/vehicles/{id}/photos

Every photo of the vehicle as a job object, in walkaround order.

200 OK
{
  "data": [
    {
      "id": "Hn4kR2pXq8VbT1sLw0Za",
      "status": "completed",
      "backdrop": "grey-concrete",
      "vehicle_id": "pQ7mT2vK9cLx4RbN1sHd",
      "name": "stock-4471",
      "output_url": "https://firebasestorage.googleapis.com/v0/b/…/default.jpg?alt=media&token=…",
      "photo_quality": "good",
      "angle": "front",
      "error": null,
      "credits_charged": 1,
      "seconds": 62,
      "created_at": "2026-10-14T09:41:12.000Z",
      "completed_at": "2026-10-14T09:42:14.000Z"
    },
    {
      "id": "Tq9cW3nLx7HbR2kPv5Ms",
      "status": "completed",
      "backdrop": "grey-concrete",
      "vehicle_id": "pQ7mT2vK9cLx4RbN1sHd",
      "name": "stock-4471",
      "output_url": "https://firebasestorage.googleapis.com/v0/b/…/default.jpg?alt=media&token=…",
      "photo_quality": "good",
      "angle": "front34_right",
      "error": null,
      "credits_charged": 1,
      "seconds": 62,
      "created_at": "2026-10-14T09:41:12.000Z",
      "completed_at": "2026-10-14T09:42:14.000Z"
    }
  ]
}

Send to your feed

POST/v1/vehicles/{id}/feed

Uploads the vehicle's finished photos to the feed set up in Settings, in walkaround order, named by VIN or stock number. Needs Feed export set up and the VIN or stock number its naming uses. An account can send 30 times an hour. If the server refuses part way, the answer is 502 feed_failed with a reason and how many photos were sent.

الترويسات

Idempotency-Keystring
أي نص فريد حتى 255 حرفًا، مثل UUID. اختياري.
200 OK
{
  "ok": true,
  "sent": 8
}

Backdrops

عرض الخلفيات

GET/v1/backdrops

جميع الخلفيات الـ 13، ولكل منها صورة معاينة.

200 OK
{
  "data": [
    {
      "slug": "grey-concrete",
      "name": "Grey concrete",
      "preview_url": "https://lotshow.com/assets/looks/grey.jpg"
    },
    {
      "slug": "white-hall",
      "name": "White hall",
      "preview_url": "https://lotshow.com/assets/looks/original.jpg"
    },
    {
      "slug": "white-tiles",
      "name": "White tiles",
      "preview_url": "https://lotshow.com/assets/looks/tiles.jpg"
    },
    {
      "slug": "micro-cement",
      "name": "Micro-cement",
      "preview_url": "https://lotshow.com/assets/looks/cement.jpg"
    },
    {
      "slug": "stone",
      "name": "Stone",
      "preview_url": "https://lotshow.com/assets/looks/stone.jpg"
    },
    {
      "slug": "plain-stone",
      "name": "Plain stone",
      "preview_url": "https://lotshow.com/assets/looks/stoneflat.jpg"
    },
    {
      "slug": "dealership",
      "name": "Dealership",
      "preview_url": "https://lotshow.com/assets/looks/dealer.jpg"
    },
    {
      "slug": "marble-hall",
      "name": "Marble hall",
      "preview_url": "https://lotshow.com/assets/looks/marble.jpg"
    },
    {
      "slug": "photo-booth",
      "name": "Photo booth",
      "preview_url": "https://lotshow.com/assets/looks/booth.jpg"
    },
    {
      "slug": "white-studio",
      "name": "White studio",
      "preview_url": "https://lotshow.com/assets/looks/studio.jpg"
    },
    {
      "slug": "white-hall-plain",
      "name": "White hall, plain walls",
      "preview_url": "https://lotshow.com/assets/looks/originalflat.jpg"
    },
    {
      "slug": "white-tiles-plain",
      "name": "White tiles, plain walls",
      "preview_url": "https://lotshow.com/assets/looks/tilesflat.jpg"
    },
    {
      "slug": "micro-cement-plain",
      "name": "Micro-cement, plain walls",
      "preview_url": "https://lotshow.com/assets/looks/cementflat.jpg"
    }
  ]
}

جلب خلفية

GET/v1/backdrops/{slug}

One backdrop. An unknown slug answers 404 backdrop_not_found.

200 OK
{
  "slug": "micro-cement",
  "name": "Micro-cement",
  "preview_url": "https://lotshow.com/assets/looks/cement.jpg"
}

Credits

جلب الرصيد

GET/v1/credits

The shared balance across the web Studio and the API, with the plan it comes from. renews is a date, or null without a monthly plan.

200 OK
{
  "balance": 320,
  "plan": "elite",
  "monthly_credits": 1000,
  "renews": "2026-11-13"
}

الاستخدام اليومي

GET/v1/credits/usage

Photos spent per day, oldest first.

Query parameters

daysinteger
Between 1 and 90. Defaults to 14.
200 OK
{
  "days": [
    {
      "date": "2026-10-13",
      "spent": 35
    },
    {
      "date": "2026-10-14",
      "spent": 29
    }
  ]
}

فحص الحالة

فحص الحالة

GET/v1/health

يردّ بـ {"ok": true} ما دام الـ API يعمل. لا يحتاج إلى مفتاح.

200 OK
{
  "ok": true
}

Webhooks

تسجيل نقطة استقبال

POST/v1/webhooks

Up to 5 endpoints per account. Send a JSON body.

Parameters

urlstringrequired
A public https URL.
eventsstring[]
Any of job.completed, job.failed, vehicle.completed, credits.low. Defaults to the first two.
201 Created
{
  "id": "Wk2pR8sN4vQx1LmT6cZa",
  "url": "https://yourdms.com/hooks/lotshow",
  "events": [
    "job.completed",
    "job.failed"
  ],
  "created_at": "2026-10-14T09:30:05.000Z"
}

عرض نقاط الاستقبال

GET/v1/webhooks

Every endpoint registered on the account.

200 OK
{
  "data": [
    {
      "id": "Wk2pR8sN4vQx1LmT6cZa",
      "url": "https://yourdms.com/hooks/lotshow",
      "events": [
        "job.completed",
        "job.failed"
      ],
      "created_at": "2026-10-14T09:30:05.000Z"
    }
  ]
}

إرسال حدث تجريبي

POST/v1/webhooks/{id}/test

Posts a sample event named test to the endpoint and reports how it answered.

200 OK
{
  "delivered": true,
  "status_code": 200,
  "ms": 142
}

حذف نقطة استقبال

DELETE/v1/webhooks/{id}

Stops sending events to it.

200 OK
{
  "id": "Wk2pR8sN4vQx1LmT6cZa",
  "deleted": true
}

Errors

Failures use a normal HTTP status and a JSON body with a stable code you can branch on.

402
{
  "error": {
    "code": "insufficient_credits",
    "message": "Not enough credits. Top up on https://lotshow.com/settings?tab=billing"
  }
}
StatusCodeMeaning
400invalid_requestالطلب غير سليم: معرّف أو معامل أو محتوى أو ترويسة غير صالحة.
400image_requiredلم يُرسَل ملف image ولا image_url.
400unknown_backdropقيمة backdrop ليست أحد المعرّفات الـ 13.
400bad_webhookيجب أن يكون webhook رابط https عامًا.
400image_unreachableتعذّر تنزيل image_url.
400image_unreadableالملف ليس صورة JPEG أو PNG أو WebP.
401missing_keyلا توجد ترويسة Authorization: Bearer.
401invalid_keyالمفتاح غير سليم أو غير معروف أو أُلغي.
402insufficient_creditsالرصيد لا يكفي لهذه المهمة.
403plan_requiredالحساب ليس على باقة «احترافي» أو «النخبة».
403email_not_verifiedأكّد البريد الإلكتروني للحساب أولًا.
403account_blockedلا يستطيع الحساب بدء مهام جديدة.
403not_approvedلم تتم الموافقة على الحساب بعد.
404not_foundلا توجد نقطة نهاية كهذه، أو لا توجد نقطة استقبال webhook بهذا المعرّف.
404job_not_foundلا توجد مهمة بهذا المعرّف في هذا الحساب.
404vehicle_not_foundلا توجد سيارة بهذا vehicle_id.
404backdrop_not_foundلا توجد خلفية بهذا المعرّف.
409limit_reachedلدى الحساب بالفعل 5 نقاط استقبال webhook.
409idempotency_conflictاستُخدم Idempotency-Key مع محتوى مختلف، أو أن طلبه الأول ما زال قيد التنفيذ.
409vehicle_existsAnother vehicle on the account already has that VIN or stock number. Its id is in vehicle_id.
409no_photosThe vehicle has no finished photos to send.
409feed_not_configuredFeed export isn't set up in Settings.
409vin_requiredThe feed names files by VIN and the vehicle has no 17 character VIN.
409stock_requiredThe feed names files by stock number and the vehicle has none.
413image_too_largeيمكن أن يصل حجم الصور إلى 15 ميغابايت.
429rate_limitedطلبات أو مهام كثيرة جدًا. خفّف السرعة وأعد المحاولة.
429feed_limit_reachedThe account has sent to its feed 30 times this hour.
502feed_failedThe feed server refused the connection or the upload. reason says why and sent how many photos landed.
503busyالمعالجة متوقفة للحظات. أعد المحاولة بعد قليل.
500internalحدث خطأ من جهتنا. أعد المحاولة.

Limits

LimitValue
Requests per key120 per minute, bursts up to 120
Live keys per account10
Webhook endpoints per account5
Image size15 MB
Webhook response time10 seconds
Page size for lists100
Feed sends per account30 per hour, 60 photos each

Rate limit headers

Each key has a bucket of 120 tokens that refills at 2 a second. A request spends one token and creating a job spends two, so an idle key can burst and a steady client gets 120 requests a minute. Every answer says where you stand:

HeaderValue
RateLimit-Policy120;w=60;burst=120
RateLimitlimit=120, remaining=97, reset=12: tokens left, and seconds until the bucket is full again.
X-RateLimit-Limit120
X-RateLimit-RemainingTokens left.
X-RateLimit-ResetSeconds until the bucket is full again.
Retry-AfterOn a 429 only: seconds to wait before retrying.

Need more throughput? Talk to us.