Skip to main content

Vista API Documentation

Integrate map and plan georeferencing into your applications.

The Vista API georeferences uploaded map/plan images against Ordnance Survey tiles using deep learning embeddings and fine registration. Two core operations power the pipeline:

  • Search (Coarse) — finds the approximate geographic location of your image using vector similarity search.
  • Match (Fine Registration) — aligns your image to OS tiles at pixel level using feature matching (SuperPoint + LightGlue).
All coordinates use EPSG:27700 (British National Grid) — not WGS84 / lat-lon.

Authentication

All API requests must include an API key passed as an Ocp-Apim-Subscription-Key HTTP header:

curl -H "Ocp-Apim-Subscription-Key: YOUR_API_KEY" /v1/jobs
API keys are provisioned via the Azure Marketplace when you subscribe to a Vista plan. Contact your administrator if you need a key.

Quick Start

Get a georeferenced result in three steps:

1
Submit a job

Upload your plan image with a bounding box defining the search area.

curl -X POST /v1/jobs \ -H "Ocp-Apim-Subscription-Key: YOUR_API_KEY" \ -F "file=@plan.png" \ -F "bbox=530000,180000,534000,184000" \ -F "effort=low"

Returns a job_id and resolved effort with HTTP 202 Accepted.

2
Poll for status

Check the job until it completes (poll no more than every 10 seconds).

curl /v1/jobs/{job_id} \ -H "Ocp-Apim-Subscription-Key: YOUR_API_KEY"
3
Fetch the result

Once the status is complete, retrieve the georeferencing result.

curl /v1/jobs/{job_id}/result \ -H "Ocp-Apim-Subscription-Key: YOUR_API_KEY"

Job Submission

Full Pipeline (Coarse + Fine)

POST /v1/jobs

Runs the complete georeferencing pipeline: coarse vector search followed by fine registration.

ParameterTypeRequiredDescription
fileFileYesThe plan/map image to georeference (PNG or JPEG, max 20 MB)
bboxStringNoBounding box search area: min_x,min_y,max_x,max_y in EPSG:27700. Maximum 10 km × 10 km. Improves accuracy when provided.
effortStringNoSearch effort: low, medium (default), or high. Controls how many candidates are evaluated — see Effort Levels

Fine Registration Only

POST /v1/jobs/fine-register

Skips coarse search and performs only fine registration against the specified bounds.

ParameterTypeRequiredDescription
fileFileYesThe plan/map image (PNG or JPEG, max 20 MB)
boundsStringYesKnown bounds: min_x,min_y,max_x,max_y in EPSG:27700. Maximum 10 km × 10 km.
effortStringNoFine registration effort: low, medium (default), or high. Controls fallback depth — see Effort Levels

File Validation

  • Accepted formats: PNG and JPEG (validated by magic bytes, not just extension)
  • Maximum file size: 20 MB
  • Images should be north-oriented for best results

Bounding Box Validation

  • Format: min_x,min_y,max_x,max_y — four comma-separated numbers in EPSG:27700
  • Maximum dimensions: 10 km × 10 km (10,000 m per side)
  • Max values must be strictly greater than min values

Response (202 Accepted)

{ "job_id": "a1b2c3d4e5f6", "status": "queued", "effort": "medium" }

Effort Levels

Control the trade-off between speed and thoroughness with the effort parameter. Effort affects both the coarse search (number of candidates evaluated) and fine registration (fallback depth).

LevelCoarse CandidatesFine RegistrationTypical Use
low 5 candidates Minimal fallbacks, fastest Accurate bbox and want fast turnaround
medium 10 candidates (default) Balanced fallback depth General purpose — recommended starting point
high 15 candidates Full fallbacks including tiled and satellite Difficult images, large search areas, or when medium fails

The value is case-insensitive. When omitted, defaults to medium. The resolved effort level is returned in the 202 response.

Start with low effort and escalate only if the result quality is insufficient.
High effort can take substantially longer to process as it evaluates more candidates with full fallback strategies including tiled and satellite matching. Only use when medium effort fails to produce acceptable results.

Job Status

GET /v1/jobs/{job_id}

Returns the current status of a submitted job.

StatusDescription
queuedJob is waiting to be picked up by a worker
processingJob is actively being processed
completeProcessing finished — result is available
failedProcessing failed — see error message

Response Example

{ "job_id": "a1b2c3d4e5f6", "status": "processing", "progress": "Running fine registration...", "error": null, "created_at": "2026-03-06T10:30:00Z", "started_at": "2026-03-06T10:30:02Z", "completed_at": null }

Job Results

GET /v1/jobs/{job_id}/result

Retrieve the georeferencing result once the job status is complete. There are three possible outcomes:

Successful Match

{ "job_id": "a1b2c3d4e5f6", "success": true, "approximate": false, "matched_tile_id": "SU_41_14_25k", "matched_pack_id": "pack_bristol_01", "similarity_score": 0.87, "search_time_ms": 245.3, "aligned_image_bounds": [530012.5, 180045.2, 530512.5, 180545.2], "reference_bounds": [530000.0, 180000.0, 531000.0, 181000.0], "num_keypoints_query": 1024, "num_keypoints_ref": 2048, "num_matches": 512, "num_inliers": 380, "inlier_ratio": 0.74, "ncc_score": 0.92, "combined_score": 0.85, "num_gcps": 380, "processing_time_sec": 12.4 }

Approximate Match

Coarse location found but fine registration failed. The bounds are estimated, not pixel-accurate. A suggestion field may offer guidance.

{ "job_id": "a1b2c3d4e5f6", "success": true, "approximate": true, "approximate_tile_id": "TQ_3877_7521_1x1", "approximate_bounds": [538770.0, 175210.0, 539026.0, 175466.0], "approximate_similarity": 0.72, "error_message": "Fine matching failed: insufficient inliers", "suggestion": "Try a larger or higher-resolution image", "processing_time_sec": 8.1 }

Failed Match

{ "job_id": "a1b2c3d4-...", "success": false, "error_message": "No matching tiles found within search area", "processing_time_sec": 5.3 }

Image Downloads

GET /v1/jobs/{job_id}/aligned-image

Downloads the aligned output image (PNG). Only available after a successful match.

GET /v1/jobs/{job_id}/query-image

Downloads the original uploaded query image.

# Download aligned result curl -o aligned.png /v1/jobs/{job_id}/aligned-image \ -H "Ocp-Apim-Subscription-Key: YOUR_API_KEY" # Download original upload curl -o original.png /v1/jobs/{job_id}/query-image \ -H "Ocp-Apim-Subscription-Key: YOUR_API_KEY"

Rate Limits

To ensure fair usage and system stability, the following limits are enforced:

Queue Limit

Each user can have a maximum of 10 queued jobs at any time. Only jobs with queued status count toward this limit — jobs that are processing, complete, or failed do not.

If the limit is reached, new submissions return HTTP 429 Too Many Requests:

{ "error": "Queue limit reached: you already have 10 queued job(s). Maximum allowed is 10. Please wait for existing jobs to complete before submitting new ones." }
The queue limit applies to both /v1/jobs and /v1/jobs/fine-register endpoints. Wait for existing jobs to start processing before submitting new ones.

Job Management

The Management API uses a separate base path: /v1/manage/*

List Jobs

GET /v1/manage/jobs
ParameterTypeDescription
statusStringFilter by status: queued, processing, complete, failed
typeStringFilter by job type: pipeline, fine_register
from_dateStringISO 8601 date — only jobs created after this date
to_dateStringISO 8601 date — only jobs created before this date
sortStringSort order: desc (default, newest first) or asc (oldest first)
page_sizeIntegerResults per page (default 25, max 100)
continuationStringContinuation token for pagination

Get Job Detail

GET /v1/manage/jobs/{job_id}

Returns full job details including status, parameters, and result.

Delete Job

DELETE /v1/manage/jobs/{job_id}

Permanently deletes a job and its associated images. Clients can only delete their own jobs (returns 403 otherwise).

curl -X DELETE /v1/manage/jobs/{job_id} \ -H "Ocp-Apim-Subscription-Key: YOUR_API_KEY"

Dashboard Statistics

GET /v1/manage/stats

Returns aggregate job statistics. Clients see only their own stats; admins see all users.

ParameterTypeDescription
from_dateStringISO 8601 date — filter by start date
to_dateStringISO 8601 date — filter by end date
{ "total": 142, "by_status": { "queued": 3, "processing": 1, "complete": 130, "failed": 8 }, "by_type": { "pipeline": 100, "fine_register": 42 }, "success_rate": 0.94 }

Best Practices

  1. Bbox accuracy is critical — the closer the bounding box is to the real location, the better the results. Maximum size is 10 km × 10 km, but smaller is better for accuracy and speed.
  2. Try low effort first — escalate to medium or high only if the result quality is insufficient. This saves processing time and cost.
  3. North-oriented images — source images should be north-up and cropped to the main map content for best accuracy.
  4. Annotations are OK — borders, padding, legends, north arrows, and red-lining are tolerated. The system ignores them during matching.
  5. Scale matters — best results between 1:1,000 and 1:5,000. Outside this range, accuracy may drop.
  6. Poll interval — check job status no more than every 10 seconds to avoid rate limiting.
  7. Job TTL — completed jobs and their images expire after approximately 90 days.
  8. Queue limit — you can have a maximum of 10 queued jobs at a time. Wait for jobs to start processing before submitting more.
  9. High effort is slowhigh effort evaluates significantly more candidates and can take substantially longer. Use only when medium fails.

Error Handling

Failed jobs return HTTP 200 with "success": false in the result body. Always check the success field — do not rely on HTTP status alone.
ScenarioHTTP StatusDetails
Job completed (check success field)200Result body contains success: true or success: false with error_message
Result requested before job completes409 ConflictJob is still processing — continue polling the status endpoint
Job not found404 Not FoundInvalid job ID or job has expired
Invalid file type, too large, or bad bbox400 Bad RequestCheck file format (PNG/JPEG), size (< 20 MB), and bbox dimensions (≤ 10 km × 10 km)
Missing or invalid API key401 UnauthorizedCheck your Ocp-Apim-Subscription-Key header
Accessing another user's job403 ForbiddenClients can only access and delete their own jobs
Queue limit exceeded429 Too Many RequestsYou have 10 queued jobs. Wait for existing jobs to process before submitting new ones.

Response Reference

Complete reference of all fields returned in the job result response.

FieldTypeDescription
job_idstringUnique 12-character hex identifier for the job
successbooleantrue if a match was found, false otherwise
approximatebooleantrue if only coarse location was found (fine registration failed)
matched_tile_idstringIdentifier of the best-matching OS tile
matched_pack_idstringIdentifier of the embedding pack containing the matched tile
similarity_scorefloatCosine similarity score from coarse search (0–1)
search_time_msfloatTime taken for the coarse vector search in milliseconds
aligned_image_boundsarrayGeoreferenced bounds as [min_x, min_y, max_x, max_y] in EPSG:27700
reference_boundsarrayBounds of the reference tile used for matching as [min_x, min_y, max_x, max_y]
num_keypoints_queryintegerNumber of keypoints detected in the query image
num_keypoints_refintegerNumber of keypoints detected in the reference tile
num_matchesintegerTotal number of feature matches before RANSAC filtering
num_inliersintegerNumber of inlier feature matches after RANSAC
inlier_ratiofloatRatio of inliers to total matches (0–1). Higher is better.
ncc_scorefloatNormalised cross-correlation between aligned image and reference tile
combined_scorefloatWeighted combination of similarity, inlier ratio, and NCC scores
num_gcpsintegerNumber of ground control points used in the alignment
processing_time_secfloatTotal processing time in seconds
error_messagestringHuman-readable error description (present when success is false or approximate is true)
suggestionstringGuidance for improving results (present on approximate matches)

Approximate Match Fields

When approximate is true, these fields replace the standard match fields:

FieldTypeDescription
approximate_tile_idstringBest-matching tile from coarse search
approximate_boundsarrayEstimated bounds as [min_x, min_y, max_x, max_y] — not pixel-accurate
approximate_similarityfloatSimilarity score of the approximate match