Markup Generation
The markup generator creates property boundary markup documents using aerial imagery. Unlike single-shot endpoints, this is a multi-step flow requiring human input between phases.
Overview
The markup flow has 5 steps:
| Step | Endpoint | What Happens |
|---|---|---|
| 1 | POST /v1/markup/generate | Start generation -- captures aerial screenshots and enhances with AI |
| 2 | GET /v1/markup/jobs/{jobId} | Poll until awaiting_input -- orientation variants are ready |
| 3 | POST /v1/markup/jobs/{jobId}/select | Select which orientation to use |
| 4 | POST /v1/markup/jobs/{jobId}/annotate | Submit annotated boundary + clean image |
| 5 | POST /v1/markup/jobs/{jobId}/video | (Optional) Generate cinematic video |
Flow Diagram
POST /v1/markup/generate
|
v
Job created (status: queued)
|
v
Background processing...
|
v
Status: awaiting_input
(orientation_variants available)
|
v
POST /v1/markup/jobs/{id}/select
|
v
Status: running (annotation_ready)
|
v
POST /v1/markup/jobs/{id}/annotate
|
v
Status: completed
|
v (optional)
POST /v1/markup/jobs/{id}/videoStep 1: Start Generation
curl -X POST \
-H "X-API-Key: dome_live_your_key" \
-H "Content-Type: application/json" \
-d '{"address": "42 Wallaby Way, Sydney NSW 2000"}' \
https://api.domeagent.com.au/v1/markup/generateBehind the scenes, the system captures aerial screenshots from multiple angles and enhances them with AI. This typically takes 30-90 seconds.
Step 2: Poll for Orientation Variants
Poll every 5 seconds until status changes to awaiting_input. The response includes orientation variants:
{
"data": {
"id": "d56ef78a-...",
"status": "awaiting_input",
"output": {
"orientation_variants": [
{
"key": "bottom",
"preview_url": "https://storage.domeagent.com.au/markup/...-bottom-preview.jpg",
"enhanced_url": "https://storage.domeagent.com.au/markup/...-bottom-enhanced.jpg"
},
{
"key": "left",
"preview_url": "https://storage.domeagent.com.au/markup/...-left-preview.jpg",
"enhanced_url": "https://storage.domeagent.com.au/markup/...-left-enhanced.jpg"
}
]
}
}
}Display the preview_url images to the user so they can choose the best aerial view.
Step 3: Select Orientation
curl -X POST \
-H "X-API-Key: dome_live_your_key" \
-H "Content-Type: application/json" \
-d '{"orientation": "bottom"}' \
https://api.domeagent.com.au/v1/markup/jobs/{jobId}/selectThe response includes a selected_url -- the high-resolution enhanced image for annotation.
Step 4: Submit Annotation
After the user draws property boundaries on the selected image, submit the annotated and clean image URLs:
curl -X POST \
-H "X-API-Key: dome_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"annotated_image_url": "https://your-storage.com/annotated.jpg",
"clean_image_url": "https://your-storage.com/clean.jpg"
}' \
https://api.domeagent.com.au/v1/markup/jobs/{jobId}/annotateStep 5: Generate Video (Optional)
Generate a cinematic flyover video from the completed markup:
curl -X POST \
-H "X-API-Key: dome_live_your_key" \
-H "Content-Type: application/json" \
-d '{}' \
https://api.domeagent.com.au/v1/markup/jobs/{jobId}/videoThis returns a new job ID. Poll GET /v1/jobs/{videoJobId} for the video result.
Complete Code Example
const API_KEY = "dome_live_your_key";
const BASE_URL = "https://api.domeagent.com.au/v1";
async function api(path, options) {
const res = await fetch(`${BASE_URL}${path}`, {
...options,
headers: {
"X-API-Key": API_KEY,
"Content-Type": "application/json",
...options?.headers,
},
});
return res.json();
}
async function pollUntil(jobId, targetStatus) {
while (true) {
const { data } = await api(`/markup/jobs/${jobId}`);
console.log(`Status: ${data.status}`);
if (data.status === targetStatus) return data;
if (data.status === "failed") throw new Error("Job failed");
await new Promise((r) => setTimeout(r, 5000));
}
}
// Step 1: Start generation
const { data: job } = await api("/markup/generate", {
method: "POST",
body: JSON.stringify({ address: "42 Wallaby Way, Sydney NSW 2000" }),
});
// Step 2: Wait for orientation variants
const awaitingJob = await pollUntil(job.job_id, "awaiting_input");
const variants = awaitingJob.output.orientation_variants;
// Step 3: Select orientation
const { data: selection } = await api(`/markup/jobs/${job.job_id}/select`, {
method: "POST",
body: JSON.stringify({ orientation: "bottom" }),
});
// Step 4: Submit annotation
await api(`/markup/jobs/${job.job_id}/annotate`, {
method: "POST",
body: JSON.stringify({
annotated_image_url: "https://your-storage.com/annotated.jpg",
clean_image_url: "https://your-storage.com/clean.jpg",
}),
});
// Step 5: (Optional) Generate video
const { data: videoJob } = await api(`/markup/jobs/${job.job_id}/video`, {
method: "POST",
body: JSON.stringify({}),
});UI Integration Tips
- Step 1-2: Show a loading spinner while the job processes. Display a progress indicator.
- Step 2-3: Display orientation preview images side-by-side. Let the user click to select.
- Step 3-4: Show the selected high-res image with a boundary drawing canvas overlay.
- Step 4: Upload the annotated and clean images to your own storage, then submit the URLs.
- Step 5: Show a “Generate Video” button after annotation is complete.
Next Steps
- Jobs and Polling -- General polling patterns
- API Reference -- Full endpoint documentation
- Live Demo -- Try the API from your browser