For the complete documentation index, see llms.txt. This page is also available as Markdown.

OSCP GeoPose Protocol

Localize against MultiSet maps using Open AR Cloud's GeoPose Protocol, so an OSCP client needs no MultiSet-specific code.

Overview

POST /v1/vps/map/geopose speaks Open AR Cloud's GeoPose Protocol. An OSCP client can point at MultiSet and localize without knowing anything MultiSet-specific.

It answers with the same localization quality as Map Query, and meters against your plan the same way. What differs is the shape of the request and the response.

If you are building on MultiSet directly, use Map Query. This endpoint exists for interoperability: use it when you already have an OSCP client, or when you need to be one of several interchangeable providers behind a standard interface.

Not to be confused with GeoPose Support, which describes the GeoPose object returned inside a normal MultiSet localization response. That is a field on an existing API. This is a separate endpoint speaking the full protocol.

Protocol versions

Versions 1.0 and 2.0 are both accepted, and the two are detected by the shape of the request:

Version

sensorReadings

Camera intrinsics

1.0

Flat array

On the Sensor

2.0

Object of typed arrays

On the reading

The version travels in the Accept header and is echoed in the response Content-Type:

Accept: application/vnd.oscp+json;version=2.0

It defaults to 2.0 when the header is absent. An unrecognised version is a 400.

Choosing which map to query

The GeoPose spec's body carries no map field, so there are two ways to scope a request.

Approach
How

By coordinate (spec-native)

Include a geolocationReading. The nearest map whose geo-fence is in range is resolved and queried.

Explicitly (MultiSet extension)

Pass mapCode or mapSetCode as a query parameter.

The query parameters take precedence over any geolocationReading. mapCode and mapSetCode are mutually exclusive.

The endpoint

Localize using the OSCP GeoPose Protocol

post

Localize using Open AR Cloud's GeoPose Protocol, so an OSCP client can use MultiSet maps without MultiSet-specific code. Protocol versions 1.0 and 2.0 are both accepted and detected from the request. The version travels in the Accept header and is echoed in the response. The spec's body carries no map field. Supply a geolocationReading and the nearest map in range is used, or name one with the mapCode / mapSetCode query parameters, which take precedence. Images must be upright and non-mirrored.

Authorizations
AuthorizationstringRequired
Bearer authentication header of the form Bearer <token>.
Query parameters
mapCodestringOptional

Scope to one map. Takes precedence over any geolocationReading.

mapSetCodestringOptional

Scope to a map set. Mutually exclusive with mapCode.

queryModestring · enumOptionalDefault: vps-1Possible values:
Header parameters
AcceptstringOptional

Protocol version negotiation. Supported - 1.0, 2.0. An unknown version is a 400.

Default: application/vnd.oscp+json;version=2.0
Body
idstringRequired
timestampnumberRequired

Milliseconds since the Unix epoch.

typestringRequiredExample: geopose
sensorReadingsone ofRequired

v2 object of typed arrays, or the v1 flat array. Detected by shape.

or
priorPosesobject[]Optional

Accepted by the spec; not consumed.

Responses
200

A GeoPoseResp. The quaternion is in the OGC LTP-ENU frame (+X east, +Y north, +Z up, right-handed).

application/vnd.oscp+json
idstringOptional
timestampnumberOptional
typestringOptionalExample: geopose
post/vps/map/geopose
POST /v1/vps/map/geopose HTTP/1.1
Host: api.multiset.ai
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 540

{
  "id": "b8f1c2d4-0000-4000-8000-000000000000",
  "timestamp": 1789557904000,
  "type": "geopose",
  "sensors": [
    {
      "id": "cam0",
      "type": "camera"
    },
    {
      "id": "gps0",
      "type": "geolocation"
    }
  ],
  "sensorReadings": {
    "cameraReadings": [
      {
        "timestamp": 1789557904000,
        "sensorId": "cam0",
        "size": [
          1024,
          1024
        ],
        "imageBytes": "<base64 JPEG>",
        "imageOrientation": {
          "mirrored": false,
          "rotation": 0
        },
        "params": {
          "model": "PINHOLE",
          "modelParams": [
            512,
            512,
            512,
            512
          ]
        }
      }
    ],
    "geolocationReadings": [
      {
        "timestamp": 1789557904000,
        "sensorId": "gps0",
        "latitude": 37.794853,
        "longitude": -122.394573,
        "altitude": 5.74
      }
    ]
  }
}
{
  "id": "b8f1c2d4-0000-4000-8000-000000000000",
  "timestamp": 1789557905123,
  "accuracy": {
    "position": 1,
    "orientation": 5
  },
  "type": "geopose",
  "geopose": {
    "position": {
      "lat": 37.7948528,
      "lon": -122.3945734,
      "h": 6.47
    },
    "quaternion": {
      "x": -0.0127,
      "y": -0.0007,
      "z": -0.0539,
      "w": 0.9985
    }
  }
}

Image requirements

Images must be upright and non-mirrored. Send imageOrientation with rotation: 0 and mirrored: false, or rotate the image before encoding it.

This matches the requirement on the native query API. A rotated or mirrored frame does not fail loudly, it simply fails to localize, so it is worth asserting in your client rather than discovering in the field.

When no pose is found

A request that cannot be localized returns a 404 with a reason. The one worth handling separately is:

That means no geo-fence was within range of the coordinate you supplied, which is a different problem from a map being found and the image failing to match. The first is a coverage or geo-referencing issue, the second is an imagery issue. Treat them differently in your client.

Accuracy values

The response carries position and orientation accuracy. These are nominal values rather than a per-query estimate, so do not read them as a confidence score for an individual pose. Use the confidence field on Map Query when you need that.

Last updated

Was this helpful?