Replica Link API
Replica Link embeds an HTTP server inside the Replica Pro macOS app, exposing a REST API on the local network. All endpoints return JSON unless otherwise noted.
- Base URL:
http://<local-ip>:8247 - Protocol: HTTP (TLS available but disabled by default)
- Authentication: PIN-based, with Bearer token for subsequent requests
Quick Start
# 1. Authenticate
TOKEN=$(curl -s -X POST http://192.168.1.10:8247/api/auth \
-H "Content-Type: application/json" \
-d '{"pin":"482193"}' | jq -r '.token')
# 2. List projects
curl -s http://192.168.1.10:8247/api/projects \
-H "Authorization: Bearer $TOKEN" | jq
# 3. Upload a new project
curl -s -X POST http://192.168.1.10:8247/api/projects \
-H "Authorization: Bearer $TOKEN" \
-F "name=TestProject" \
-F "images=@photo1.jpg" \
-F "images=@photo2.jpg" | jq
# 4. Start computation
curl -s -X POST http://192.168.1.10:8247/api/projects/<project-id>/compute \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"detail":"medium"}' | jq
# 5. Poll status
curl -s http://192.168.1.10:8247/api/status \
-H "Authorization: Bearer $TOKEN" | jq
# 6. Download model
curl -s -o model.glb \
http://192.168.1.10:8247/api/projects/<project-id>/download?format=glb \
-H "Authorization: Bearer $TOKEN"
Authentication
All endpoints except POST /api/auth and GET /api/health require authentication via:
- Header:
Authorization: Bearer <token> - Query parameter:
?token=<token>(for contexts where headers can't be set, e.g.<model-viewer>)
Tokens expire after 24 hours.
Health Check
/api/health
Health check endpoint. No authentication required.
Response 200
{
"status": "ok",
"version": "1.0"
}
Authenticate
/api/auth
Authenticate with the 6-digit PIN displayed in the Replica desktop app.
Request Body
{
"pin": "482193"
}
Response 200
{
"token": "550e8400-e29b-41d4-a716-446655440000"
}
Errors
| Status | Body | Cause |
|---|---|---|
400 |
{"error": "Invalid request body"} |
Malformed JSON |
401 |
{"error": "Invalid PIN"} |
Wrong PIN |
Projects
List Projects
/api/projects
Returns all projects.
Response 200
{
"projects": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "MyProject",
"imageCount": 42,
"status": "completed",
"progress": 1.0,
"processingStage": "",
"hasModel": true,
"hasGlb": true,
"modelDetail": "medium",
"errorMessage": ""
}
]
}
Get Project
/api/projects/:id
Get a single project's details.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id |
UUID string | Project persistent ID |
Response 200 — Same structure as a single item in the project list.
Errors
| Status | Cause |
|---|---|
404 |
Project not found |
Create Project
/api/projects
Create a new project by uploading images.
Content-Type: multipart/form-data
Form Fields
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | No | Project name. Defaults to LinkUpload_<timestamp> |
images |
file[] | Yes | One or more image files |
Supported image formats: jpg, jpeg, png, heif, heifs, raw, tif, tiff
Response 201
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "MyProject",
"imageCount": 42,
"status": "ready"
}
Errors
| Status | Cause |
|---|---|
400 |
No images provided, unsupported format, or invalid content type |
412 |
Upload directory not configured in the desktop app |
500 |
Failed to create project folder |
Rename Project
/api/projects/:id
Rename a project. Renames both the project and its folder on disk.
Request Body
{
"name": "NewProjectName"
}
Validation rules:
- Name cannot be empty
- Name cannot contain
/or\ - Cannot rename a project that is currently processing or queued
- Destination folder must not already exist
Response 200
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "NewProjectName"
}
Errors
| Status | Cause |
|---|---|
400 |
Empty name, path separators, already processing, or folder conflict |
404 |
Project not found |
Delete Project
/api/projects/:id
Delete a project. Optionally removes files from disk.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
deleteFiles |
string | "false" |
Set to "true" to also delete the project folder from disk |
Response 200
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"deleted": true
}
Errors
| Status | Cause |
|---|---|
404 |
Project not found |
Images
Add Images
/api/projects/:id/images
Add images to an existing project.
Content-Type: multipart/form-data
Form Fields
| Field | Type | Required | Description |
|---|---|---|---|
images |
file[] | Yes | One or more image files |
Response 200
{
"imageCount": 58,
"addedCount": 16
}
| Field | Description |
|---|---|
imageCount |
Total image count after adding |
addedCount |
Number of images successfully added |
Errors
| Status | Cause |
|---|---|
400 |
No images provided or invalid content type |
404 |
Project not found |
Get Image Thumbnail
/api/projects/:id/images/:filename
Serve a single image as a JPEG thumbnail.
- Max size: 400px (longest side)
- Format: JPEG, quality 0.7
- Content-Type:
image/jpeg
Errors
| Status | Cause |
|---|---|
404 |
Project or image not found |
500 |
Failed to generate thumbnail |
Download All Images
/api/projects/:id/images/download
Download all project images as a ZIP archive.
- Content-Type:
application/zip - Content-Disposition:
attachment; filename="<project-name>_images.zip"
Errors
| Status | Cause |
|---|---|
400 |
Project has no images |
404 |
Project not found |
500 |
Failed to create ZIP archive |
Computation
Start Computation
/api/projects/:id/compute
Start photogrammetry computation on a project.
Preconditions:
- Project status must be
readyorcompleted - Project must have at least one image
Request Body (all fields optional — defaults to medium detail)
{
"detail": "medium",
"sampleOrdering": "unordered",
"featureSensitivity": "normal",
"meshPrimitive": "triangle",
"isObjectMaskingEnabled": false
}
Standard Parameters
| Field | Values | Default | Description |
|---|---|---|---|
detail |
preview, reduced, medium, full, raw, custom |
medium |
Reconstruction detail level |
sampleOrdering |
unordered, sequential |
unordered |
Photo capture ordering hint |
featureSensitivity |
normal, high |
normal |
Feature detection sensitivity |
meshPrimitive |
triangle, quad |
triangle |
Output mesh primitive type |
isObjectMaskingEnabled |
true, false |
false |
Automatic object masking |
Custom Detail Parameters (only when detail is "custom")
| Field | Type | Description |
|---|---|---|
maximumPolygonCount |
int | Max polygon count |
maximumTextureDimension |
string | oneK, twoK, fourK, eightK, sixteenK |
textureFormat |
string | png, jpeg |
jpegCompressionQuality |
float | 0.0 – 1.0 (only with jpeg format) |
outputTextureMaps |
string[] | ["all"] or subset: ambientOcclusion, diffuseColor, displacement, normal, roughness |
Response 202
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "queued"
}
Errors
| Status | Cause |
|---|---|
404 |
Project not found |
409 |
Project is already processing or queued |
Cancel Computation
/api/projects/:id/cancel
Cancel an ongoing or queued computation.
Preconditions: Project status must be processing or queued.
Response 200
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "ready"
}
Errors
| Status | Cause |
|---|---|
404 |
Project not found or not currently processing |
3D Models
Serve Model
/api/projects/:id/model
Serve the GLB model for use with <model-viewer> or similar 3D viewers.
- Content-Type:
model/gltf-binary
Errors
| Status | Cause |
|---|---|
404 |
GLB model not available |
Serve Model (Viewer)
/api/viewer/projects/:id/model
Same as above, but accepts authentication via query parameter instead of header. Designed for <model-viewer> which cannot send custom headers.
Query Parameters
| Parameter | Required | Description |
|---|---|---|
token |
Yes | Session token |
Note: This endpoint does NOT go through the auth middleware — it validates the token inline.
Download Model
/api/projects/:id/download
Download the 3D model in the requested format. Conversion is performed on-demand and cached.
Query Parameters
| Parameter | Values | Default | Description |
|---|---|---|---|
format |
glb, usdz, obj, fbx |
glb |
Output format |
Content Types
| Format | Content-Type |
|---|---|
glb |
model/gltf-binary |
usdz |
model/vnd.usdz+zip |
obj |
text/plain |
fbx |
application/octet-stream |
Behavior:
- USDZ is the native output format — served directly, no conversion needed
- GLB is auto-generated during Link workflows and cached in
link-exports/ - OBJ and FBX are generated on-demand via Blender and cached for subsequent requests
Errors
| Status | Cause |
|---|---|
400 |
Invalid format |
404 |
Project or model not found |
500 |
Conversion failed |
Status & Polling
Poll Status
/api/status
Lightweight polling endpoint. Returns minimal status for all projects plus an adaptive poll interval.
Response 200
{
"projects": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "processing",
"progress": 0.63,
"processingStage": "Mesh Generation",
"hasGlb": false,
"errorMessage": ""
}
],
"pollInterval": 2
}
| Field | Description |
|---|---|
pollInterval |
Suggested polling interval in seconds: 2 if any project is processing/queued, 10 otherwise |
Data Models
Project Status
| Value | Description |
|---|---|
ready |
Images loaded, ready for computation |
queued |
Waiting in computation queue |
processing |
Photogrammetry in progress |
completed |
Model successfully generated |
failed |
Computation failed (see errorMessage) |
LinkProjectDTO (Full)
id string UUID
name string Project folder name
imageCount int Number of images
status string Project status
progress double 0.0 – 1.0
processingStage string Current stage (e.g. "Mesh Generation")
hasModel bool USDZ model exists
hasGlb bool GLB export exists
modelDetail string Detail level used
errorMessage string Error description (empty if none)
LinkStatusProjectDTO (Lightweight)
id string UUID
status string Project status
progress double 0.0 – 1.0
processingStage string Current stage
hasGlb bool GLB export exists
errorMessage string Error description
Error Handling
All errors return a JSON body:
{
"error": "Descriptive error message"
}
HTTP Status Codes
| Code | Usage |
|---|---|
200 |
Success |
201 |
Resource created (project upload) |
202 |
Accepted (computation queued) |
400 |
Bad request (validation, malformed body) |
401 |
Unauthorized (invalid/missing token or PIN) |
404 |
Resource not found |
409 |
Conflict (project already processing) |
412 |
Precondition failed (upload directory not configured) |
500 |
Internal server error (file I/O, conversion failure) |
Server Configuration
| Parameter | Default | Notes |
|---|---|---|
| Port | 8247 |
Falls back to 8248+ if in use |
| Protocol | HTTP | TLS available but disabled by default |
| Session expiry | 24 hours | Automatic |
| PIN length | 6 digits | Regenerable from desktop UI |