Skip to content

Inventory API

The Inventory API writes stock into Vyro: from a dealer management system, a feed, or your own platform. To read stock, use the GraphQL API.

Environment Base URL
Staging https://inventory-api.vyrolabs-staging.net
Production Asia-Pacific https://inventory-api.vyro.com.au
Production Europe https://inventory-api.vyro-eu.com

The OpenAPI specification is at /spec on each host, with no token needed. Point a code generator at it for a typed client.

Use the same bearer token as the GraphQL API (Authentication). Each batch has a source_name that says who owns the vehicles:

Client source_name Can write to
User client user:<the user's id>, or leave it out Showrooms that user belongs to
App client app:<your app code> Showrooms that installed your app

Vehicles are keyed by source_name plus your source_id. Sending the same source_id again updates the vehicle.

  1. POST up to 100 vehicles (or 2 MB) to /batch.

    Terminal window
    curl -s https://inventory-api.vyrolabs-staging.net/batch \
    -H "Authorization: Bearer $ACCESS_TOKEN" \
    -H 'Content-Type: application/json' \
    -d @batch.json
    {
    "source_name": "user:3f2a9c1e-5b7d-4e8a-9c0f-1a2b3c4d5e6f",
    "items": [
    {
    "showroom_ids": ["9b1d4e7a-2c3f-4a5b-8d6e-7f8091a2b3c4"],
    "vehicle": {
    "source_id": "STK-1042",
    "stock_id": "1042",
    "condition": "used",
    "production_year": "2022",
    "make": "Hyundai",
    "model": "Kona",
    "badge": "Active",
    "vin": "KMHK281EMNU000000",
    "odometer": 38500,
    "colour": "Ultimate Red",
    "body_type": "SUV",
    "fuel_type": "petrol",
    "transmission": "Automatic",
    "is_published": true,
    "is_listed": true,
    "is_sold": false,
    "estimated_delivery_delay": 0,
    "pricing": {
    "type": "basic",
    "price": 2299000,
    "currency": "AUD"
    }
    },
    "location": { "source_id": "sydney", "name": "Example Motors Sydney" },
    "assets": [
    { "type": "image", "placement": "featured", "order": 0, "src": "https://example.com/1042/front.jpg" },
    { "type": "image", "placement": "gallery", "order": 0, "src": "https://example.com/1042/side.jpg" },
    { "type": "image", "placement": "gallery", "order": 1, "src": "https://example.com/1042/interior.jpg" }
    ]
    }
    ]
    }

    You get a job id back straight away, with status 201:

    { "job_id": "6859392d-d604-4ca6-8842-28494e2bbc1b" }
  2. Poll the job at GET /jobs/{job_id} until status is completed. Batches usually finish within a minute.

    {
    "id": "6859392d-d604-4ca6-8842-28494e2bbc1b",
    "status": "completed",
    "errors": [],
    "image_moderation": [
    {
    "index": 4,
    "accepted": [{ "src": "https://ik.imagekit.io/vyro/…" }],
    "rejected": [{ "src": "…", "original_src": "https://example.com/1042/banner.jpg" }]
    }
    ]
    }
  3. Read the result with GraphQL, by source_id, to get each vehicle’s id and code.

    query Imported($sourceIds: [String!]!) {
    stocked_vehicles(where: { source_id: { _in: $sourceIds } }) {
    id
    code
    source_id
    is_published
    }
    }

source_id, production_year (a string such as "2022"), make, model, condition (new, used or demo), is_published, is_listed, is_sold and estimated_delivery_delay (days until it can be delivered; 0 if it’s on the lot). Everything else is optional, but the more you send, the better the listing. The specification lists every field.

  • odometer is in kilometres.
  • fuel_type is one of petrol, diesel, electric, hybrid, plug-in-hybrid, hydrogen, lpg.
  • Dates are YYYY-MM-DD.

Prices are in cents. Choose one of two shapes.

pricing (basic): one price, used for every state the showroom sells in.

"pricing": { "type": "basic", "price": 2299000, "currency": "AUD", "excls_on_roads": false }

advanced_pricing: a full price per state. Use this when drive-away prices differ by state, which in Australia they usually do.

"advanced_pricing": {
"type": "advanced",
"items": [
{
"pricing_code": "AU_NSW",
"version": "v2",
"driveAwayPrice": 3069000,
"lineItems": {
"dutiable": [{ "code": "vehicle-price", "value": 2850000 }],
"onRoad": [{ "code": "stamp-duty", "value": 114000 }, { "code": "registration", "value": 105000 }],
"additional": []
}
},
{
"pricing_code": "AU_VIC",
"version": "v2",
"driveAwayPrice": 3099000,
"lineItems": { "dutiable": [{ "code": "vehicle-price", "value": 2850000 }], "onRoad": [{ "code": "on-road-costs", "value": 249000 }], "additional": [] }
}
]
}

A vehicle is only offered in the states you send. To calculate state drive-away prices, use the Pricing API.

  • src must be a public HTTPS URL. Vyro downloads each image, checks it, and re-hosts it on its image CDN, so the src you read back is different from the one you sent.
  • placement is featured for the hero (one per vehicle) and gallery for the rest. order counts from 0 within each placement.
  • Images are checked against Vyro’s acceptable use policy. Rejected ones (for example, text-only promotional graphics) are listed in the job’s image_moderation.rejected, with your original_src.

Send the vehicle again in a batch with the same source_id and the new flags:

  • Sold: is_sold: true. Its page stays up and says it’s sold.
  • Hidden from lists, still reachable by link: is_listed: false.
  • Off the site: is_published: false.

Send the whole vehicle each time, including its images, because a batch item replaces the vehicle.

  • 100 vehicles or 2 MB per batch.
  • 10,000 requests per minute. Above that you get 429 Too Many Requests: back off and retry.