Convert any image into an AR model and embed it on your website with one line of HTML.
Every API request must include your API key in the X-API-Key header. Keep this key secret — never expose it in client-side JavaScript on a public page.
| Header | Value |
|---|---|
| X-API-Key | Your VISIONARI_API_KEY |
Add one script tag and one div to your HTML. The widget handles everything: submits the image, waits for conversion, and renders the AR viewer automatically.
<!-- 1. Load the widget script once, anywhere in the page -->
<script src="https://visionarispace.com/api/v1/widget.js"></script>
<!-- 2. Place a div where you want the AR widget to appear -->
<div
data-visionari-image="https://your-cdn.com/product.jpg"
data-visionari-key="YOUR_API_KEY"
data-visionari-variant="interactive"
style="width:400px; height:480px;"
></div>
<script src="https://visionarispace.com/api/v1/widget.js"></script>
<div
data-visionari-image="https://your-cdn.com/product.jpg"
data-visionari-key="YOUR_API_KEY"
data-visionari-variant="static"
style="width:400px; height:480px;"
></div>
| Attribute | Required | Description |
|---|---|---|
| data-visionari-image | Yes* | Public URL of the image to convert. Use this OR data-visionari-job. |
| data-visionari-job | Yes* | An existing job_id from a previous /convert call. Use this OR data-visionari-image. |
| data-visionari-key | Yes | Your API key. |
| data-visionari-variant | No | interactive (default) or static. |
By default, the API reads the uploaded image's pixel dimensions and automatically sets the AR plane to the correct proportions — a 900×600 landscape image produces a 36″×24″ plane with no distortion. You can override this in two ways.
Omit all dimension parameters. The API detects the pixel size and computes proportional inches (24″ base for the shorter side). Square images stay at 24″×24″.
{
"image_url": "https://cdn.example.com/mural-900x600.jpg"
}
Result: AR plane is 36″×24″ (3:2 ratio)
aspect_ratioPass a ratio string when you know the proportions but not the exact inches. Format: "W:H". The API sets 24″ for the shorter side and scales the other accordingly.
{
"image_url": "https://cdn.example.com/mural.jpg",
"aspect_ratio": "3:2"
}
Other examples: "16:9" → 42.67″×24″ | "2:3" (portrait) → 24″×36″ | "1:1" → 24″×24″
width_inches + height_inchesProvide both values for precise physical sizing. Both must be supplied together (0.1–120 inches each). Overrides aspect_ratio if also present.
{
"image_url": "https://cdn.example.com/mural.jpg",
"width_inches": 48,
"height_inches": 32
}
Your backend calls /api/v1/convert, gets a job_id, stores it, then passes it to the widget div in your HTML. The API key never touches the browser.
import requests
response = requests.post(
"https://visionarispace.com/api/v1/convert",
headers={
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json"
},
json={
"image_url": "https://your-cdn.com/product.jpg"
# Dimensions are auto-detected from the image pixels.
# Use aspect_ratio="3:2" for landscape/mural images, or
# supply width_inches + height_inches for precise control.
}
)
data = response.json()
job_id = data["job_id"] # e.g. "api_a1b2c3d4..."
# Store job_id in your database or session
const response = await fetch('https://visionarispace.com/api/v1/convert', {
method: 'POST',
headers: {
'X-API-Key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
image_url: 'https://your-cdn.com/product.jpg'
// Dimensions are auto-detected from the image pixels.
// Use aspect_ratio: '3:2' for landscape/mural images, or
// supply width_inches + height_inches for precise control.
})
});
const data = await response.json();
const jobId = data.job_id; // e.g. "api_a1b2c3d4..."
// Store jobId in your database or session
$ch = curl_init('https://visionarispace.com/api/v1/convert');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'X-API-Key: YOUR_API_KEY',
'Content-Type: application/json'
],
CURLOPT_POSTFIELDS => json_encode([
'image_url' => 'https://your-cdn.com/product.jpg'
// Dimensions are auto-detected from the image pixels.
// Use 'aspect_ratio' => '3:2' for landscape/mural images, or
// supply 'width_inches' + 'height_inches' for precise control.
])
]);
$data = json_decode(curl_exec($ch), true);
$jobId = $data['job_id']; // e.g. "api_a1b2c3d4..."
// Store $jobId in your database or session
<script src="https://visionarispace.com/api/v1/widget.js"></script>
<!-- Interactive -->
<div
data-visionari-job="api_a1b2c3d4..."
data-visionari-key="YOUR_API_KEY"
data-visionari-variant="interactive"
style="width:400px; height:480px;"
></div>
<!-- Static -->
<div
data-visionari-job="api_a1b2c3d4..."
data-visionari-key="YOUR_API_KEY"
data-visionari-variant="static"
style="width:400px; height:480px;"
></div>
If you need to wait for completion before rendering (e.g. for server-side HTML rendering), poll the status endpoint:
import time
while True:
r = requests.get(
f"https://visionarispace.com/api/v1/status/{job_id}",
headers={"X-API-Key": "YOUR_API_KEY"}
)
status = r.json()["status"]
if status == "completed":
break
elif status == "failed":
raise Exception("Conversion failed")
time.sleep(3)
result = requests.get(
f"https://visionarispace.com/api/v1/result/{job_id}",
headers={"X-API-Key": "YOUR_API_KEY"}
).json()
embed_url = result["embed_url"] # animated, clickable
embed_url_static = result["embed_url_static"] # display only
async function waitForResult(jobId) {
while (true) {
const r = await fetch(`https://visionarispace.com/api/v1/status/${jobId}`, {
headers: { 'X-API-Key': 'YOUR_API_KEY' }
});
const data = await r.json();
if (data.status === 'completed') break;
if (data.status === 'failed') throw new Error('Conversion failed');
await new Promise(res => setTimeout(res, 3000));
}
const result = await fetch(`https://visionarispace.com/api/v1/result/${jobId}`, {
headers: { 'X-API-Key': 'YOUR_API_KEY' }
}).then(r => r.json());
return {
embedUrl: result.embed_url, // animated, clickable
embedUrlStatic: result.embed_url_static // display only
};
}
Animated "Powered by VisionARI" badge with shimmer. Shows a "View in Your Space" button. On iOS launches USDZ Quick Look; on Android opens Scene Viewer. Best for product pages and showrooms.
Plain text badge, no animation, no button. Shows the Space Visual image only. Ideal for email-embedded previews, PDFs, or anywhere interaction is not possible.
After the script loads, window.VisionARI is available with two methods:
// Mount using a pre-existing job ID
VisionARI.mount('#my-container', {
jobId: 'api_a1b2c3d4...',
apiKey: 'YOUR_API_KEY',
variant: 'interactive' // or 'static'
});
// Submit image and auto-render (image_url mode)
VisionARI.embed('#my-container', {
imageUrl: 'https://your-cdn.com/product.jpg',
apiKey: 'YOUR_API_KEY',
variant: 'static'
});
Pass an optional callback_url in the convert request. VisionARI will POST to it when conversion completes (or fails), so you don't need to poll.
requests.post(
"https://visionarispace.com/api/v1/convert",
headers={"X-API-Key": "YOUR_API_KEY"},
json={
"image_url": "https://your-cdn.com/product.jpg",
"callback_url": "https://yourapp.com/visionari/webhook"
}
)
# Your webhook endpoint receives:
# POST /visionari/webhook
# {
# "job_id": "api_a1b2c3d4...",
# "status": "completed", # or "failed"
# "embed_url": "...",
# "embed_url_static": "...",
# "usdz_url": "...",
# "glb_url": "..."
# }
| Parameter | Type | Required | Description |
|---|---|---|---|
| image_url | string | Yes | Public HTTP/HTTPS URL of the image to convert. |
| aspect_ratio | string | No | Convenience shorthand, e.g. "3:2", "16:9", "1:1". Computes width/height from ratio (24" base for shorter side). Ignored when width_inches + height_inches are both supplied. |
| width_inches | float | No | Physical width in inches. Auto-detected from image when omitted. Range: 0.1–120. Must be paired with height_inches. |
| height_inches | float | No | Physical height in inches. Auto-detected from image when omitted. Range: 0.1–120. Must be paired with width_inches. |
| callback_url | string | No | Webhook URL to notify on completion. |
Response 202: { "job_id": "api_...", "status": "queued" }
| Field | Type | Description |
|---|---|---|
| status | string | queued | processing | completed | failed |
| progress | float | 0–100 percentage complete. |
| Field | Description |
|---|---|
| embed_url | Interactive widget URL (animated, clickable AR launch). |
| embed_url_static | Static widget URL (display only). |
| widget_script_url | URL of widget.js to include in your page. |
| models.usdz.url | Direct Supabase URL to the USDZ model file (iOS AR). |
| models.glb.url | Direct Supabase URL to the GLB model file (Android AR). |
| dimensions | Physical dimensions used for the model (width_inches, height_inches). |
Public JavaScript loader. Include once per page with a <script> tag.