Skip to main content
Documentation

Quickstart

Upload a panorama, trigger an Argus/VGGT reconstruction task, and poll for output.

This guide follows the domestic reconstruction task flow and adapts it to the overseas gateway. The public product name is Argus; endpoint paths still use vggt.

Submit App request

Argus is reviewed before production use. Submit an App request from /dashboard/apps/apply and include:

  • App name - the product or integration that will use Argus.
  • Production use case - the workflow, why AI reconstruction is needed, and the approximate monthly panorama volume.
  • Contact name - the person Realsee can contact during review.
  • Contact email - the address the Realsee developer team can use during review.

The request is automatically scoped to the active Team from your signed-in session; Team ownership is not editable in the form. After approval, the provisioned Developer app appears in the Team dashboard. Use its app key and app secret only on your backend.

Install the uploader

npm install @realsee/universal-uploader@0.1.1 cos-js-sdk-v5@1.8.3

Argus uses the uploader to send the panorama to the temporary storage location returned by the gateway.

Get an Argus gateway token

Exchange your reviewed Developer app credentials for an Argus gateway access token. This is separate from the regular OpenAPI auth docs because Argus has its own reviewed gateway surface.

export async function getArgusAccessToken() {
  const body = new URLSearchParams({
    app_key: process.env.REALSEE_APP_KEY!,
    app_secret: process.env.REALSEE_APP_SECRET!,
  })

  const response = await fetch('https://app-gateway.realsee.ai/auth/access_token', {
    method: 'POST',
    headers: { 'content-type': 'application/x-www-form-urlencoded' },
    body,
  })

  if (!response.ok) throw new Error(`Argus auth failed: ${response.status}`)
  const payload = await response.json() as {
    code: number
    status: string
    data: { access_token: string }
  }
  if (payload.code !== 0) throw new Error(`Argus auth failed: ${payload.status}`)
  return payload.data.access_token
}

Create an upload token

Send an empty input_image_id to start a new upload session. The gateway returns the stable identifier that must be reused for upload, trigger, and poll requests.

import type { UploadToken } from '@realsee/universal-uploader'

export async function createArgusUpload(accessToken: string) {
  const response = await fetch('https://app-gateway.realsee.ai/open/saas/v1/vggt/upload/token', {
    method: 'POST',
    headers: {
      authorization: `${accessToken}`,
      'content-type': 'application/json',
    },
    body: JSON.stringify({ input_image_id: '' }),
  })

  if (!response.ok) throw new Error(`Upload token failed: ${response.status}`)
  const payload = await response.json() as {
    code: number
    status: string
    data: {
      input_image_id: string
      upload_token: UploadToken
    }
  }
  if (payload.code !== 0) throw new Error(`Upload token failed: ${payload.status}`)

  return {
    inputImageId: payload.data.input_image_id,
    uploadToken: payload.data.upload_token,
  }
}

The response follows the gateway envelope used by other internal service calls: { code, status, data } with success code 0. Pass data.upload_token to the uploader, and retain data.input_image_id for the remaining requests.

Upload panoImage.jpg

The domestic walkthrough fixes the object key to panoImage.jpg. Keep that name unless your Realsee contact gives you a different contract.

Use Uploader.defaultUploadHandler for stable defaults, then override only when your file size requires different multipart settings.

import {
  Uploader,
  type ProviderAdaptor,
  type UploadToken,
} from '@realsee/universal-uploader'

const cosAdaptor: ProviderAdaptor = () => import('@realsee/universal-uploader/adaptors/cos')

export async function uploadArgusPanorama(file: File, uploadToken: UploadToken) {
  const uploader = new Uploader(cosAdaptor, {
    getToken: async () => uploadToken,
  })

  return uploader.upload('panoImage.jpg', file, {
    parallel: Uploader.defaultUploadHandler.parallel,
    partSize: Uploader.defaultUploadHandler.partSize,
    retry: Uploader.defaultUploadHandler.retry,
  })
}

Trigger reconstruction

After upload succeeds, trigger the Argus/VGGT task with the same input_image_id.

export async function triggerArgusTask(accessToken: string, inputImageId: string) {
  const response = await fetch('https://app-gateway.realsee.ai/open/saas/v1/vggt/trigger', {
    method: 'POST',
    headers: {
      authorization: `${accessToken}`,
      'content-type': 'application/json',
    },
    body: JSON.stringify({
      input_image_id: inputImageId,
      type: 'pano',
    }),
  })

  if (!response.ok) throw new Error(`Argus trigger failed: ${response.status}`)
  return response.json()
}

Poll until complete

Poll GET /open/saas/v1/vggt/poll with both type and input_image_id.

export async function pollArgusTask(accessToken: string, inputImageId: string) {
  const url = new URL('https://app-gateway.realsee.ai/open/saas/v1/vggt/poll')
  url.searchParams.set('type', 'pano')
  url.searchParams.set('input_image_id', inputImageId)

  for (let attempt = 0; attempt < 90; attempt += 1) {
    const response = await fetch(url, {
      headers: { authorization: `${accessToken}` },
    })

    if (!response.ok) throw new Error(`Argus poll failed: ${response.status}`)
    const payload = await response.json() as {
      code: number
      status: string
      data: {
        status: 'pending' | 'success' | 'failed'
        alg_task_id?: string
        result_url?: string
        failed_reason?: string
      }
    }
    if (payload.code !== 0) throw new Error(`Argus poll failed: ${payload.status}`)
    const data = payload.data

    if (data.status === 'success') return data
    if (data.status === 'failed') throw new Error('Argus task failed')

    await new Promise((resolve) => setTimeout(resolve, 2000))
  }

  throw new Error('Argus task timed out')
}

Successful responses can include result_url. The public schema guarantees only that this value is a URI; the media type and direct Five SDK compatibility depend on the provisioned integration.

Stable route summary

Use these stable docs URLs while building: