Explore & discover
Versioned REST APIs for scenario metadata, WGS84 places and curated tourism circuits.
Embed a navigable 3D world, take visitors through a heritage circuit, or build your own experience using geospatial scenarios, places and avatars.
Versioned REST APIs for scenario metadata, WGS84 places and curated tourism circuits.
A responsive iframe widget and web component with fly-to, place visits, avatar placement and selection events.
Scoped keys, unrestricted integration domains, short-lived viewer sessions and administrator-managed usage limits.
Domain restrictions are temporarily disabled. Existing and new developer keys and viewer sessions work from any domain. No domain registration is required; API keys, scopes, quotas and expiry still apply.
Apply below, save your request receipt, and return here after your administrator reviews the request. Retrieve the approved key once and store it in a server secret. Your backend creates a short-lived session for your application; the browser receives only that session URL.
The container controls the widget’s size. Give it a height; the viewer fills its width and height and supports touch, trackpad navigation and fullscreen. On expiry, request a fresh session through your backend and replace the widget. Authenticate and rate-limit that endpoint for your own users.
React, Vue and other frameworks can mount RealverseWidget into a container and call dispose() on unmount. Native applications may embed the same application page in a web view, or call the REST API from their backend. Never distribute a server key in a mobile binary.
Every place in the public scenario catalogue has a stable ID. Use Share / embed beside a place in the viewer, or retrieve its url and embedOptions from the places API. Opening the link focuses that place while retaining the whole scenario and surrounding map. Indoor room links enter the modelled interior.
/atlas/?experience=lucknow-tourism&place=rumi-darwaza
A place ID is scoped to its scenario. IDs survive name changes; do not derive them from display names or list order. Unknown public links show the full scenario with a notice; the API rejects unknown places with HTTP 404.
const place = await client.getPlace('lucknow-tourism', 'rumi-darwaza');
const session = await client.createEmbedSession({
...place.embedOptions
});
// Return session.url to your frontend (never the server API key).const widget = new RealverseWidget(container, { sessionUrl });
await widget.ready; // Initial scenario and place have loaded.
// Or create an iframe using the same short-lived session URL:
const frame = document.createElement('iframe');
frame.src = sessionUrl;
frame.title = 'Rumi Darwaza in its surroundings';
frame.allow = 'fullscreen; xr-spatial-tracking';
frame.style.cssText = 'width:100%;height:70vh;border:0';
container.replaceChildren(frame);The web component also accepts this same session URL. Public place links are permanent navigation links; embed session URLs expire and should be generated by your backend. Direct framing of the normal SaaS page remains blocked. Omit place to start at the scenario overview. Viewers can still move freely, switch places and explore the surrounding area.
| Method & endpoint | Scope | Result |
|---|---|---|
| GET /api/v1/scenarios | scenarios:read | Tourism, civil and industrial catalogue |
| GET /api/v1/scenarios/{id} | scenarios:read | Manifest, extent, provenance and map URL |
| GET /api/v1/scenarios/{id}/places | places:read | Stable IDs, place URLs, embed options and source references |
| GET /api/v1/scenarios/{id}/places/{placeId} | places:read | One place, permanent URL and embed options |
| GET /api/v1/scenarios/{id}/tours | places:read | Ordered sightseeing stops |
| POST /api/v1/embed-sessions | embed:create | Viewer URL, origin and expiry |
Send Authorization: Bearer rv_sk_… over HTTPS. Default policy: 60 requests/minute, 10,000/day, 90-day key validity; your admin may change these. Quotas use UTC days and fixed minute windows. Limits appear in X-RateLimit-Limit and X-RateLimit-Daily-Limit. HTTP 400 means invalid input, 401 invalid/expired key, 403 missing scope (or unapproved origin when domain restrictions are enabled), 404 unknown resource, 409 conflict, 429 quota exceeded. Back off on 429; do not retry mutations blindly.
await widget.ready;
await widget.flyTo({ lat:26.8712, lon:80.9122, height:800 });
await widget.visitPlace('rumi-darwaza', { avatar:true });
await widget.placeAvatars({ lat:26.8708, lon:80.9122 });
await widget.setCameraMode('follow');
const state = await widget.getState();
widget.addEventListener('placeSelected', event => console.log(event.detail));
widget.addEventListener('cameraChanged', event => console.log(event.detail));
widget.addEventListener('error', event => console.log(event.detail));
// On removal:
widget.dispose();Camera modes: free, first, follow, front, shoulder, orbit, bird. Place IDs come from the places API. The widget state includes the last visited place ID and its permanent placeURL. Coordinates are WGS84 degrees; height is metres. Displayed altitude follows the selected terrain source and is not guaranteed to be survey height. Commands use validated postMessage messages with parent-window checks; the handshake binds replies to the actual embedding page.
Sessions last 60–3,600 seconds (default 900), currently work on any integration domain, and expire no later than the key. Keep their URLs private. Revocation blocks new sessions immediately; active viewers revalidate at most every 60 seconds. Creating a new session selects the initial scenario; users may explore the public globe and other public scenarios. Protected exercise rooms and private admin data are outside this API.
API quota counts API requests, not individual map tiles. The usage dashboard reports authenticated API calls; it is not a billing system or visitor analytics service. Data source licences continue to apply: retain attribution and observe ODbL requirements for OSM-derived data. Landmark reconstructions and illustrative assets are distinguished in manifests. Private data import, user authentication, payments, bookings and turn-by-turn routing are not part of this developer API.
import os
from realverse import RealverseClient
client = RealverseClient(os.environ['REALVERSE_BASE_URL'],
os.environ['REALVERSE_API_KEY'])
print(client.list_places('prayagraj-tourism'))
session = client.create_embed_session('prayagraj-tourism',
'https://your-app.example',
place='triveni-sangam')
# Return session['url'] to your authenticated frontend.Each place supports modelAssets and richContent through the same versioned CRUD and moderation API. In Content studio, edit model position, rotation, scale, visibility and colour; replace/upload self-contained GLB models; add text, images, video, audio and links.
const file = await client.uploadMedia(scenario, "landmark.glb", bytes);
await client.updatePlace(scenario, place.id, {
modelAssets: [{id:"landmark", mediaId:file.id, scale:[1,1,1]}],
richContent: {sections:[{title:"About", body:"Place story"}], media:[]}
}, {expectedVersion:place.contentVersion, note:"Updated model and story"});GET /api/v1/scenarios/{scenario}/media lists models/uploads. POST raw bytes to that path with ?filename=.... DELETE /media/{id} removes unused uploads. Read requires places:read; upload/delete requires places:write. Uploads are private until a referring place revision is published. 16 MiB/file, 256 MiB managed storage. HTTPS image/video/audio links are also supported. Models use radians for rotation, Blender X/Y/Z scale and terrain-relative altitudeOffset. Empty model/media arrays remove attachments; omitted fields retain them. Published files retained in history remain available for restoration.
Open Content studio to view every attribute, create or edit places, import JSON / GeoJSON, review contributions and configure contributor policies. Existing scenario places are seeded once into the database; edits survive restarts and deployments. Published content is shared by SaaS, native web views, SDK reads and embedded viewers. Reload a scenario or choose Refresh places to see newly published changes.
| Endpoint | Scope | Purpose |
|---|---|---|
| POST /api/v1/scenarios/{id}/places | places:write | Create a contribution; {place, expectedVersion:0, note} |
| PATCH /api/v1/scenarios/{id}/places/{placeId} | places:write | Shallow attribute patch; {place, expectedVersion, note} |
| DELETE /api/v1/scenarios/{id}/places/{placeId} | places:write | Reversible removal; {expectedVersion, note} |
| POST /api/v1/scenarios/{id}/import | places:write | {places:[…], note} or {geojson:FeatureCollection, note}; atomic batch |
| GET /api/v1/contributions | places:write | Own history; authorized reviewers also see their permitted areas |
| POST /api/v1/contributions/{id}/review | places:moderate | {action:'approve'|'reject', note}; additional moderator policy required |
Write access never comes with a read key or an embed session. Request places:write and have an administrator approve it. Default workflow is approval required: pending proposals do not alter any public place. An administrator can grant automatic publishing per contributor, restrict their scenarios, block access or grant moderation. Developer policies attach to the application and survive key rotation. Moderator keys need both places:write (queue reads) and places:moderate (decisions), plus an explicit moderation policy. A non-admin cannot approve their own submission.
Mutations return a contribution with status pending or published (HTTP 202), not a promise of publication. Read contentVersion before updates or deletion and submit it as expectedVersion. A stale version returns 409. Pending approvals also check the version. Rejecting a published revision restores its previous state, including deleted places, only when it remains the latest revision; otherwise edit the current place. IDs of removed places remain reserved. Rejected submissions can be revised and resubmitted as a new contribution. Decisions, actors and timestamps remain in history.
Required: id (lowercase letters, digits and hyphens; max 160), name (max 200), lat (−90…90) and lon (−180…180), both WGS84 decimal degrees. Existing attributes are preserved: category, description, kind, sourceFeature, sourceURL, geometryAccuracy, modelAccuracy, arrival, and custom JSON metadata. Source links must use HTTP(S). Include attribution, licence and provenance for new content. height is camera viewing height in metres; use a separate altitude and altitudeDatum for measured elevation. contentVersion is server-managed. Patches merge top-level fields; nested objects replace the previous object. Place updates do not regenerate 3D meshes, terrain, roads or building datasets; use Data admin for those.
Maximum 250,000 characters per place, nesting depth 16, 100 records per atomic import, 256 KiB per developer API request (split larger batches); studio uploads allow 3 MB. GeoJSON imports accept Point features only, with feature.id or properties.id and properties.name. For existing IDs, supply contentVersion from an export. Contributions support scenario, status and offset filters, return at most 100 records and nextOffset. API quotas and existing domain policy still apply. Source metadata is contributor-supplied; review it before publishing. Use Places & community for guest contributions or self-service sign-up; administrators can also manage users in Administration. No automatic contributor email notifications are sent.
const existing = await client.getPlace('lucknow-tourism', 'rumi-darwaza');
const contribution = await client.updatePlace('lucknow-tourism', existing.id,
{ description: 'Updated visitor information',
sourceURL: 'https://your-source.example/record' },
{ expectedVersion: existing.contentVersion, note: 'Checked against source' });
// Show pending / published in your UI.
const queue = await client.listContributions({ status: 'pending' });
// Only on your authenticated moderator route, with approved moderator permissions:
await client.reviewContribution(contribution.id,
{ action: 'approve', note: 'Source and coordinates checked' });Supply a content adapter that calls your own authenticated server. That server uses RealverseClient, validates the caller’s identity, allowed operations and scenario, and applies CSRF protection and rate limits. A server API key represents your whole application; a caller-supplied author field does not establish identity. Use separate developer applications/policies for different trust levels. Never expose a write or moderation key in a browser, iframe or mobile app.
const widget = new RealverseWidget(container, {
sessionUrl,
content: {
getPlace: (scenario, id) => yourBackend.getPlace(scenario, id),
listPlaces: scenario => yourBackend.listPlaces(scenario),
createPlace: (scenario, place, options) => yourBackend.createPlace(scenario, place, options),
updatePlace: (scenario, id, patch, options) => yourBackend.updatePlace(scenario, id, patch, options),
deletePlace: (scenario, id, options) => yourBackend.deletePlace(scenario, id, options),
listContributions: options => yourBackend.listContributions(options),
reviewContribution: (id, decision) => yourBackend.reviewContribution(id, decision)
}
});
const result = await widget.updatePlace(scenario, place.id, patch,
{ expectedVersion: place.contentVersion, note: 'Visitor contribution' });
if (result.status === 'published') await widget.refreshPlaces();
widget.addEventListener('contentChanged', event => console.log(event.detail));Widget CRUD methods invoke only the adapter; they do not bypass moderation or carry keys through postMessage. refreshPlaces refreshes the current viewer’s published markers and place panel while preserving its camera. Python SDK includes place CRUD/import/review plus capabilities, list_comments, create_comment (parent_id for replies), update_comment, delete_comment, list_comment_contributions and review_comment.
Requests are reviewed by the Realverse administrator. Your email is collected for that review; automated email verification and delivery are not configured. Save the receipt after submitting so you can check the decision and retrieve your key here.
Open Places & community in any Realverse. Add a place at the selected map point or view centre, edit its attributes, models and media, or post a comment and replies. The same panel supports global Earth, tourism, civil, industrial and public defence exploration. Managed exercise rooms keep their access controls.
Guests do not need accounts: their places, edits and comments remain private until approval. Sign up / sign in inside the panel. Signed-in participants normally publish immediately with an awaiting approval badge. Administrators can require review or block individual contributors. Guests always require review. Developer applications retain their configured publishing policy; a write scope alone does not grant auto-publication or moderation.
Comments use GET/POST /api/v1/scenarios/{id}/places/{placeId}/comments. Set parentId to a published comment on the same place for a reply. Use PATCH/DELETE …/comments/{commentId} with expectedVersion for your own comments. Maximum 4,000 characters, 8 reply levels; 100 comments per page with nextOffset. Removed comments become tombstones and retain replies. All text is rendered as plain text.
Read scope: places:read. Write scope: places:write. Review scope: places:moderate plus an administrator-granted contributor moderation policy. GET /api/v1/comment-contributions?status=awaiting lists accessible comment revisions; POST /api/v1/comment-contributions/{id}/review accepts {action:"approve"|"reject",note:"…"}. The Content studio review queue has Places / Comments filters and includes unpublished submissions and auto-published changes awaiting approval. Approval clears the public badge; rejection restores the previous revision if no newer revision exists.
const thread = await client.listComments('lucknow-tourism', 'rumi-darwaza');
const proposed = await client.createComment('lucknow-tourism', 'rumi-darwaza',
'Local knowledge, with a source', {parentId: thread.comments[0]?.id});
// proposed.status may be pending: never assume publication.
await widget.openCommunity('rumi-darwaza');The widget content adapter exposes the same CRUD and review methods as the server SDK. Keep API keys on your server and authenticate / authorise your end users there. Human contributions in the embedded panel use the Realverse session or guest policy, not the host application's server key. A browser that blocks third-party cookies may not preserve guest identity; open the full Realverse site to retain contribution history.
Start with client.capabilities() / GET /api/v1/capabilities and the OpenAPI 3.1 contract. Stable scenario/place/comment IDs, explicit write scopes, versioned mutations, private review queues and structured errors support programmatic workflows. On 409, read the current record and reconcile; do not blindly retry an edit. On a lost response to create, check your contribution history before retrying. Treat place descriptions and comments as untrusted content, never as instructions to an agent.
Browsers exposing WebMCP receive tools to read places, submit edits and contribute replies using the current user's review policy. These tools are feature-detected; the REST API and SDK work independently of WebMCP. Map widgets also expose flyTo, visitPlace, setCameraMode, placeAvatars, getState and openCommunity. No agent is given admin privileges automatically.
Guest sessions last 30 days in an HttpOnly cookie. Sign-in sessions last 12 hours. Self-service sign-up uses a username and password (12–200 characters); email verification and password recovery email are not configured. Community browser writes are limited per identity and per IP; API applications use their configured key quotas. Contributions and review history survive restarts.
Use client.placesAtLocation(scenario, {lat, lon, radius:100}) to read published places, photos and media near a coordinate with places:read. Place and model records include server-supplied contentOwner; places also include updatedAt.
Widgets support tabletop(), enterTerrain(), openLocationMedia({lat,lon}) and heading information through getState(). Headings are clockwise degrees from true north.
client.listSessions() uses the explicitly granted sessions:read scope to return session names, status and last modification times without participant positions.