Polycam Content Management API

Programmatic access to Polycam workspace captures, metadata, artifacts, exports, and webhooks.

The Polycam Content Management API lets you integrate existing Polycam capture data into your own applications and workflows. You can list and retrieve captures, update capture metadata, download available artifacts, export captures to additional mesh and floorplan formats, and receive real-time webhook notifications when captures change.

Enterprise Feature The API is available to workspaces with an active Enterprise plan that includes the api add-on.

Base URL

All API v1 endpoints are served under:

https://poly.cam/api/v1

Token management endpoints (create, list, revoke) live on the main application API under a separate path:

https://poly.cam/api/account/api-tokens

Authentication

API Token Authentication

Content management endpoints require a bearer token in the Authorization header. Tokens are prefixed with poly_ followed by 64 hexadecimal characters.

Authorization: Bearer poly_abc123...def456

Key facts about API tokens:

Firebase User Authentication (Token Management Endpoints)

The token management endpoints (create / list / revoke) use Firebase authentication. Pass a valid Firebase ID token in the Authorization header:

Authorization: Bearer <firebase-id-token>

The authenticated user must be the owner of the target workspace (for personal workspaces) or have owner-level access to the organization.

Errors

The API uses conventional HTTP status codes and returns errors as JSON:

{
  "error": "Human-readable error message"
}
StatusMeaning
200Success
202Accepted — request accepted, processing asynchronously
400Bad Request — invalid parameters or body
401Unauthorized — missing or invalid authentication
403Forbidden — valid credentials but insufficient permissions
404Not Found — resource does not exist or is not in your workspace
409Conflict — a conflicting operation is already in progress
422Unprocessable Entity — resource exists but cannot be processed as requested
429Too Many Requests — rate limit or concurrent job limit exceeded
500Internal Server Error

Common 401 error messages

MessageCause
Missing Authorization headerNo Authorization header sent
Bearer authorization requiredHeader doesn't start with Bearer
Invalid API token formatToken doesn't start with poly_
Invalid API tokenToken not recognized
API token has been revokedToken was previously revoked
API token has expiredToken's expiration date has passed

Pagination

List endpoints return paginated results. Use the cursor value from a response to fetch the next page.

# First page
GET /v1/captures?limit=25

# Next page — use the cursor from the previous response
GET /v1/captures?limit=25&cursor=1706140800000

When there are no more results, the cursor field is omitted from the response.

Token Management

These endpoints let you create, list, and revoke API tokens for a workspace. They use Firebase user authentication (not API token auth).

Create an API Token

POST /api/account/api-tokens Firebase Auth

Creates a new API token for the specified workspace. The raw token value is returned only in this response — store it immediately.

Request Body

FieldTypeRequiredDescription
workspace object Yes Target workspace. Contains id (string) and type ("user" or "org").
name string Yes Human-readable label (1–100 characters).
expiresInDays number No Number of days until the token expires. Omit for a non-expiring token.

Example Request

curl -X POST https://poly.cam/api/account/api-tokens \
  -H "Authorization: Bearer <firebase-id-token>" \
  -H "Content-Type: application/json" \
  -d '{
    "workspace": { "id": "ws_abc123", "type": "org" },
    "name": "CI Pipeline Token",
    "expiresInDays": 90
  }'

Response 200

{
  "token": "poly_a1b2c3d4e5f6...64 hex chars",
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "name": "CI Pipeline Token",
  "prefix": "poly_a1b2c3d4",
  "createdAt": 1706140800000,
  "expiresAt": 1713916800000,
  "message": "Save this token now - it will not be shown again!"
}
Important The token field contains the full raw token. This is the only time it will be returned. Store it in a secure location (e.g. a secrets manager).

Error Responses

StatusReason
400Invalid user account
401Missing or invalid Firebase authentication
403User does not have permission to create tokens for this workspace

List API Tokens

GET /api/account/api-tokens Firebase Auth

Lists all API tokens for a workspace. Raw token values are never returned — only the prefix (first 13 characters) is shown.

Query Parameters

ParameterTypeRequiredDescription
workspaceId string Yes The workspace ID.
workspaceType string Yes "user" or "org"

Example Request

curl https://poly.cam/api/account/api-tokens?workspaceId=ws_abc123&workspaceType=org \
  -H "Authorization: Bearer <firebase-id-token>"

Response 200

{
  "tokens": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "CI Pipeline Token",
      "prefix": "poly_a1b2c3d4",
      "createdAt": 1706140800000,
      "createdBy": {
        "id": "user_xyz",
        "username": "alice"
      },
      "expiresAt": 1713916800000,
      "revoked": false,
      "revokedAt": undefined
    }
  ]
}

Error Responses

StatusReason
401Missing or invalid Firebase authentication
403User does not have permission to view tokens for this workspace

Revoke an API Token

DELETE /api/account/api-tokens/:tokenId Firebase Auth

Revokes an API token. Revoked tokens can no longer be used for authentication. This is a soft delete — the token record is preserved with a revokedAt timestamp.

Path Parameters

ParameterTypeDescription
tokenId string The ID of the token to revoke.

Example Request

curl -X DELETE https://poly.cam/api/account/api-tokens/550e8400-e29b-41d4-a716-446655440000 \
  -H "Authorization: Bearer <firebase-id-token>"

Response 200

{
  "success": true,
  "message": "Token revoked"
}

If the token was already revoked:

{
  "success": true,
  "message": "Token already revoked"
}

Error Responses

StatusReason
400Invalid user account
401Missing or invalid Firebase authentication
403User does not have permission to revoke this token
404Token not found

Captures

Capture endpoints let you list, retrieve, and update 3D capture metadata from your workspace. All capture endpoints require API token authentication with the content_management scope. To create captures through the API, see the Reconstruction API.

List Captures

GET /v1/captures API Token

Returns a paginated list of captures in the authenticated workspace, ordered by creation date (newest first).

Query Parameters

ParameterTypeDefaultDescription
limit integer 20 Number of captures per page. Min: 1, Max: 100.
cursor string Pagination cursor from a previous response's cursor field.
externalId string Filter captures by external reference ID. Only captures with a matching externalId are returned.
hasExternalId string Filter by whether externalId is set. Use "true" to return only captures that have an externalId, or "false" to return only captures without one.
createdAfter integer Only return captures created after this timestamp (epoch milliseconds, exclusive).
createdBefore integer Only return captures created before this timestamp (epoch milliseconds, exclusive).
tag string Filter to captures that contain this tag.

Example Request

curl https://poly.cam/api/v1/captures?limit=10 \
  -H "Authorization: Bearer poly_a1b2c3d4e5f6..."

Response 200

{
  "captures": [
    {
      "id": "cap_abc123",
      "name": "Office Scan",
      "description": "3rd floor conference room",
      "tags": ["office", "interior"],
      "createdAt": 1706140800000,
      "updatedAt": 1706141400000,
      "visibility": "private",
      "session": {
        "mode": "lidar",
        "device": "iPhone 15 Pro",
        "appVersion": "3.5.0",
        "duration": 120,
        "imported": false,
        "drone": false
      },
      "processing": {
        "status": "completed",
        "sessionDuration": 120,
        "processingDuration": 45,
        "processingVersion": "2.1.0"
      },
      "mesh": {
        "vertexCount": 150000,
        "faceCount": 300000,
        "bboxSize": [5.2, 3.1, 4.8],
        "bboxCenter": [0.0, 1.5, 0.0]
      },
      "geoData": { /* location data, if available */ },
      "availableArtifacts": [
        "thumbnail.jpg",
        "video.mp4",
        "skybox.jpg",
        "original.gltf",
        "original_geometry.bin",
        "textures/0.jpg",
        "textures/1.jpg"
      ],
      "thumbnail": "https://storage.example.com/captures/cap_abc123/thumbnail.jpg",
      "externalId": "MH-2024-456"
    }
  ],
  "cursor": "1706140800000"
}

When cursor is present in the response, pass it as a query parameter to retrieve the next page. When omitted, you've reached the end.

Error Responses

StatusReason
401Missing or invalid API token
500Internal server error

Get a Capture

GET /v1/captures/:captureId API Token

Returns metadata for a single capture. The capture must belong to the workspace associated with your API token.

Path Parameters

ParameterTypeDescription
captureId string The unique ID of the capture.

Example Request

curl https://poly.cam/api/v1/captures/cap_abc123 \
  -H "Authorization: Bearer poly_a1b2c3d4e5f6..."

Response 200

{
  "capture": {
    "id": "cap_abc123",
    "name": "Office Scan",
    // ... same shape as objects in the list response
  }
}

Error Responses

StatusReason
401Missing or invalid API token
404Capture not found or does not belong to your workspace
500Internal server error
Security note Requesting a capture that exists but belongs to a different workspace returns 404 (not 403) to avoid leaking the existence of resources in other workspaces.

Update a Capture

PATCH /v1/captures/:captureId API Token

Updates fields on a capture. Supports setting or clearing the name, description, tags, and externalId fields. At least one field must be provided.

Path Parameters

ParameterTypeDescription
captureId string The unique ID of the capture to update.

Request Body

FieldTypeRequiredDescription
name string No Display name (max 256 characters). Must not be empty.
description string No Description text (max 500 characters). Send an empty string "" to clear.
tags string[] No Array of tags (max 50 tags, each max 128 characters). Send an empty array [] to clear.
externalId string No External reference ID (max 256 characters). Send an empty string "" to clear.

Example Request — Update name and tags

curl -X PATCH https://poly.cam/api/v1/captures/cap_abc123 \
  -H "Authorization: Bearer poly_a1b2c3d4e5f6..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Office Scan - Floor 3",
    "tags": ["office", "interior", "floor-3"]
  }'

Example Request — Set external ID

curl -X PATCH https://poly.cam/api/v1/captures/cap_abc123 \
  -H "Authorization: Bearer poly_a1b2c3d4e5f6..." \
  -H "Content-Type: application/json" \
  -d '{ "externalId": "MH-2024-456" }'

Example Request — Clear external ID

curl -X PATCH https://poly.cam/api/v1/captures/cap_abc123 \
  -H "Authorization: Bearer poly_a1b2c3d4e5f6..." \
  -H "Content-Type: application/json" \
  -d '{ "externalId": "" }'

Response 200

{
  "capture": {
    "id": "cap_abc123",
    "name": "Office Scan",
    "externalId": "MH-2024-456",
    // ... same shape as the Capture Object
  }
}

Error Responses

StatusReason
400No update fields provided, empty name, or field exceeds length limit
401Missing or invalid API token
404Capture not found or does not belong to your workspace

Download session.zip

GET /v1/captures/:captureId/session.zip API Token

Returns a signed download URL for the capture's source session.zip archive. For captures with source images, the archive contains the raw keyframe files under keyframes/images/.

Scope required This endpoint requires the content_management scope on the API token.

Example Request

curl https://poly.cam/api/v1/captures/550e8400-e29b-41d4-a716-446655440000/session.zip \
  -H "Authorization: Bearer poly_a1b2c3d4e5f6..."

Response 200

{
  "url": "https://storage.example.com/signed-session-zip-url?token=...",
  "expiresIn": 3600
}

Error Responses

StatusReason
401Missing or invalid API token
404Capture not found or not accessible to this token

Webhooks

Webhooks let Polycam notify your application in real time when captures in your workspace change, so you don't have to poll. You register one or more HTTPS endpoints, choose which event types you care about, and Polycam sends an HTTP POST with a JSON payload each time a matching event occurs.

Every delivery is signed with an HMAC-SHA256 signature derived from a per-endpoint signing secret so you can verify it genuinely came from Polycam. Failed deliveries are retried automatically with exponential backoff, and you can inspect event history and delivery attempts (or manually redeliver) via the webhook events endpoints.

Authentication All webhook management endpoints use the same API token authentication as the rest of the API. No special token scope is required. Endpoints are scoped to the token's workspace.

Event Types

An endpoint subscribes to one or more of the following event types:

EventFires when
capture.createdA new capture is created in the workspace.
capture.updatedAn existing capture changes in any way.
capture.deletedA capture is deleted from the workspace.
capture.updated is not a "processing complete" event It fires on every change to a capture — including metadata edits, status changes, and artifact updates — not just when processing finishes. To detect that processing has completed, inspect capture.processing.status (and, when present, capture.processing.job.status) on the payload's Capture Object.

Payload

The request body is a JSON object with the event type and the full Capture Object the event relates to. For capture.deleted, the capture object reflects the capture's state immediately before deletion.

FieldTypeDescription
eventstringOne of the event types above.
captureobjectThe full Capture Object.

Example Payload

{
  "event": "capture.updated",
  "capture": {
    "id": "cap_abc123",
    "name": "Office Scan",
    "processing": {
      "status": "completed",
      "job": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "status": "completed"
      }
    }
    // ... full Capture Object
  }
}

Verifying Signatures

Each delivery includes the following HTTP headers:

HeaderDescription
Content-TypeAlways application/json.
X-Polycam-SignatureSignature in the form sha256=<hex>, an HMAC-SHA256 of the raw request body keyed with the endpoint's signing secret.
X-Polycam-Event-IdThe ID of the webhook event being delivered. The same event ID is reused across retries and redeliveries, which makes it useful for idempotency / deduplication.

To verify a delivery, compute the HMAC-SHA256 of the exact raw request body using your endpoint's signingSecret, then compare it (using a constant-time comparison) against the hex value in the X-Polycam-Signature header:

const crypto = require('crypto');

function verifyPolycamSignature(rawBody, signatureHeader, signingSecret) {
  const expected = crypto
    .createHmac('sha256', signingSecret)
    .update(rawBody) // the raw bytes of the request body
    .digest('hex');
  const received = signatureHeader.replace('sha256=', '');
  const expectedBuf = Buffer.from(expected);
  const receivedBuf = Buffer.from(received);
  if (expectedBuf.length !== receivedBuf.length) {
    return false;
  }
  return crypto.timingSafeEqual(expectedBuf, receivedBuf);
}
Respond quickly with a 2xx A delivery is considered successful only if your endpoint responds with a 2xx status code within 10 seconds. Any other status code, a timeout, or a connection error is treated as a failure and scheduled for retry. Do heavy work asynchronously and return 200 immediately.

Delivery & Retries

Each event is delivered independently to every enabled endpoint subscribed to its event type. If a delivery fails, Polycam retries up to 8 total attempts with exponential backoff. The wait before each retry follows this schedule:

RetryWait before attempt
1st retry30 seconds
2nd retry1 minute
3rd retry5 minutes
4th retry30 minutes
5th retry2 hours
6th retry8 hours
7th retry24 hours

After the 8th failed attempt the delivery is marked failed and no longer retried. You can inspect the status of every attempt via List Deliveries, and trigger a fresh set of deliveries with Redeliver Event. Captures of the response body are truncated to 1024 characters.

Create Endpoint

POST /v1/webhooks API Token

Registers a new webhook endpoint and generates a signing secret for it.

Request Body

FieldTypeRequiredDescription
urlstringYesThe HTTPS URL to deliver events to. Must use https://.
eventsstring[]YesNon-empty array of event types to subscribe to.

Example Request

curl -X POST https://poly.cam/api/v1/webhooks \
  -H "Authorization: Bearer poly_a1b2c3d4e5f6..." \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://example.com/hooks/polycam", "events": ["capture.created", "capture.updated"] }'

Response 201

{
  "webhook": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "url": "https://example.com/hooks/polycam",
    "events": ["capture.created", "capture.updated"],
    "signingSecret": "3f9a...<64 hex chars>",
    "enabled": true,
    "createdAt": 1706140800000,
    "updatedAt": 1706140800000
  }
}
Store the signing secret The signingSecret is returned on create, on Get Endpoint, and on Rotate Secret — but it is not included in the list or update responses. You need it to verify signatures, so store it securely.

Error Responses

StatusReason
400Invalid URL format, URL is not HTTPS, or events is empty / contains an unknown event type
401Missing or invalid API token

List Endpoints

GET /v1/webhooks API Token

Lists all webhook endpoints registered for your workspace. Signing secrets are omitted.

Example Request

curl https://poly.cam/api/v1/webhooks \
  -H "Authorization: Bearer poly_a1b2c3d4e5f6..."

Response 200

{
  "webhooks": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "url": "https://example.com/hooks/polycam",
      "events": ["capture.created", "capture.updated"],
      "enabled": true,
      "createdAt": 1706140800000,
      "updatedAt": 1706140800000
    }
  ]
}

Get Endpoint

GET /v1/webhooks/:webhookId API Token

Retrieves a single webhook endpoint, including its signingSecret.

Path Parameters

ParameterTypeDescription
webhookIdstringThe ID of the webhook endpoint.

Example Request

curl https://poly.cam/api/v1/webhooks/550e8400-e29b-41d4-a716-446655440000 \
  -H "Authorization: Bearer poly_a1b2c3d4e5f6..."

Response 200

{
  "webhook": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "url": "https://example.com/hooks/polycam",
    "events": ["capture.created", "capture.updated"],
    "signingSecret": "3f9a...<64 hex chars>",
    "enabled": true,
    "createdAt": 1706140800000,
    "updatedAt": 1706140800000
  }
}

Error Responses

StatusReason
401Missing or invalid API token
404Webhook not found or does not belong to your workspace

Update Endpoint

PATCH /v1/webhooks/:webhookId API Token

Updates a webhook endpoint. All fields are optional; only the fields you provide are changed. Use enabled: false to temporarily pause deliveries without deleting the endpoint.

Request Body

FieldTypeDescription
urlstring?New HTTPS delivery URL.
eventsstring[]?New non-empty array of event types to subscribe to.
enabledboolean?Whether the endpoint is active.

Example Request

curl -X PATCH https://poly.cam/api/v1/webhooks/550e8400-e29b-41d4-a716-446655440000 \
  -H "Authorization: Bearer poly_a1b2c3d4e5f6..." \
  -H "Content-Type: application/json" \
  -d '{ "events": ["capture.created", "capture.updated", "capture.deleted"], "enabled": false }'

Response 200

Returns the updated endpoint (without signingSecret), same shape as List Endpoints items.

Error Responses

StatusReason
400Invalid URL format, URL is not HTTPS, or events provided but empty
401Missing or invalid API token
404Webhook not found or does not belong to your workspace

Delete Endpoint

DELETE /v1/webhooks/:webhookId API Token

Permanently removes a webhook endpoint. No further events are delivered to it.

Example Request

curl -X DELETE https://poly.cam/api/v1/webhooks/550e8400-e29b-41d4-a716-446655440000 \
  -H "Authorization: Bearer poly_a1b2c3d4e5f6..."

Response 200

{ "deleted": true }

Error Responses

StatusReason
401Missing or invalid API token
404Webhook not found or does not belong to your workspace

Rotate Secret

POST /v1/webhooks/:webhookId/rotate-secret API Token

Generates a new signing secret for the endpoint and returns it. The previous secret stops being valid immediately, so update your verification code to use the new secret.

Example Request

curl -X POST https://poly.cam/api/v1/webhooks/550e8400-e29b-41d4-a716-446655440000/rotate-secret \
  -H "Authorization: Bearer poly_a1b2c3d4e5f6..."

Response 200

{
  "webhook": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "url": "https://example.com/hooks/polycam",
    "events": ["capture.created", "capture.updated"],
    "signingSecret": "<new 64 hex chars>",
    "enabled": true,
    "createdAt": 1706140800000,
    "updatedAt": 1706227200000
  }
}

Error Responses

StatusReason
401Missing or invalid API token
404Webhook not found or does not belong to your workspace

List Events

GET /v1/webhook-events API Token

Lists webhook events recorded for your workspace, most recent first. An event is recorded whenever a matching capture change occurs and at least one enabled endpoint is subscribed to its type. Useful for auditing and debugging.

Query Parameters

ParameterTypeDescription
limitintegerNumber of events to return. Clamped to the range 1–100. Defaults to 20.
cursorstringPagination cursor returned by a previous response. See Pagination.
eventstringFilter to a single event type.

Example Request

curl "https://poly.cam/api/v1/webhook-events?limit=20&event=capture.updated" \
  -H "Authorization: Bearer poly_a1b2c3d4e5f6..."

Response 200

{
  "events": [
    {
      "id": "e1f2a3b4-...",
      "payload": {
        "event": "capture.updated",
        "capture": { "id": "cap_abc123" /* ... full Capture Object */ }
      },
      "createdAt": 1706140800000
    }
  ],
  "cursor": "1706140700000"
}

When cursor is present, pass it back as the cursor query parameter to fetch the next page. When it is absent, there are no more results.

Get Event

GET /v1/webhook-events/:eventId API Token

Retrieves a single webhook event, including its full payload.

Example Request

curl https://poly.cam/api/v1/webhook-events/e1f2a3b4-... \
  -H "Authorization: Bearer poly_a1b2c3d4e5f6..."

Response 200

{
  "event": {
    "id": "e1f2a3b4-...",
    "payload": { "event": "capture.updated", "capture": { /* ... */ } },
    "createdAt": 1706140800000
  }
}

Error Responses

StatusReason
401Missing or invalid API token
404Event not found or does not belong to your workspace

List Deliveries

GET /v1/webhook-events/:eventId/deliveries API Token

Lists the delivery attempts for a single event — one delivery record per subscribed endpoint. Use this to debug failing endpoints.

Example Request

curl https://poly.cam/api/v1/webhook-events/e1f2a3b4-.../deliveries \
  -H "Authorization: Bearer poly_a1b2c3d4e5f6..."

Response 200

{
  "deliveries": [
    {
      "id": "d1e2f3...",
      "eventId": "e1f2a3b4-...",
      "endpointId": "550e8400-...",
      "status": "delivered",
      "attempts": 1,
      "maxAttempts": 8,
      "lastAttemptAt": 1706140801000,
      "nextRetryAt": null,
      "httpStatus": 200,
      "responseBody": "ok",
      "error": null,
      "createdAt": 1706140800000,
      "completedAt": 1706140801000
    }
  ]
}

Delivery Fields

FieldTypeDescription
idstringUnique delivery identifier.
eventIdstringThe webhook event being delivered.
endpointIdstringThe endpoint this delivery targets.
statusstringpending, delivering, delivered, or failed.
attemptsintegerNumber of attempts made so far.
maxAttemptsintegerMaximum attempts before giving up (8).
lastAttemptAtnumber?Unix timestamp (ms) of the most recent attempt.
nextRetryAtnumber?Unix timestamp (ms) of the next scheduled retry, if pending.
httpStatusinteger?HTTP status code returned by your endpoint on the last attempt.
responseBodystring?Response body from your endpoint, truncated to 1024 characters.
errorstring?Error message for transport-level failures (e.g. timeout, DNS error).
createdAtnumberUnix timestamp (ms) when the delivery was created.
completedAtnumber?Unix timestamp (ms) when the delivery reached a terminal state.

Error Responses

StatusReason
401Missing or invalid API token
404Event not found or does not belong to your workspace

Redeliver Event

POST /v1/webhook-events/:eventId/redeliver API Token

Queues a fresh set of deliveries for an event to every currently enabled endpoint subscribed to the event's type. Useful for replaying an event after fixing a broken endpoint. The original event ID (and therefore the X-Polycam-Event-Id header) is reused.

Example Request

curl -X POST https://poly.cam/api/v1/webhook-events/e1f2a3b4-.../redeliver \
  -H "Authorization: Bearer poly_a1b2c3d4e5f6..."

Response 200

{
  "redelivered": true,
  "deliveryCount": 2
}

Error Responses

StatusReason
401Missing or invalid API token
404Event not found or does not belong to your workspace
422No enabled endpoints are subscribed to this event's type

Exports

Export endpoints let you download capture artifacts directly and convert captures to additional mesh and floorplan formats. All export endpoints require API token authentication with the content_management scope.

Download Artifacts

GET /v1/captures/:captureId/export API Token

Returns time-limited signed download URLs for all available artifacts of a capture. Each URL is valid for 1 hour (3600 seconds).

Path Parameters

ParameterTypeDescription
captureId string The unique ID of the capture.

Example Request

curl https://poly.cam/api/v1/captures/cap_abc123/export \
  -H "Authorization: Bearer poly_a1b2c3d4e5f6..."

Response 200

{
  "captureId": "cap_abc123",
  "exports": {
    "thumbnail.jpg": {
      "url": "https://storage.example.com/signed/thumbnail.jpg?token=...",
      "expiresIn": 3600
    },
    "skybox.jpg": {
      "url": "https://storage.example.com/signed/skybox.jpg?token=...",
      "expiresIn": 3600
    },
    "original.gltf": {
      "url": "https://storage.example.com/signed/original.gltf?token=...",
      "expiresIn": 3600
    },
    "original_geometry.bin": {
      "url": "https://storage.example.com/signed/original_geometry.bin?token=...",
      "expiresIn": 3600
    },
    "textures/0.jpg": {
      "url": "https://storage.example.com/signed/textures/0.jpg?token=...",
      "expiresIn": 3600
    }
  }
}

The exports object contains one entry per available artifact. Only artifacts that exist for this capture are included. See Artifacts for the full list of possible artifact names.

Error Responses

StatusReason
401Missing or invalid API token
404Capture not found, does not belong to your workspace, or the capture has no exportable artifacts
500Failed to generate export URLs

Start an Export Conversion Job

POST /v1/captures/:captureId/export API Token

Starts an asynchronous conversion job to export a capture to a different format. This supports both mesh formats (e.g. OBJ, FBX, STL) and floorplan formats (e.g. PDF, SVG, DXF, report CSV). The response includes a jobId that you can poll via GET /v1/exports/:jobId to check progress and retrieve the download URL when complete.

Path Parameters

ParameterTypeDescription
captureId string The unique ID of the capture to export.

Request Body

FieldTypeRequiredDescription
format string Yes Target export format. See Export Formats below for the full list of mesh and floorplan formats.
georeference boolean No If true, georeference the output. Only applicable to mesh point cloud formats (PLY, LAS, PTS, XYZ). Ignored for floorplan exports.
pointCloudDensity number No Point density for mesh point cloud formats (PLY, LAS, PTS, XYZ). Ignored for floorplan exports.

Example Request — Mesh export

curl -X POST https://poly.cam/api/v1/captures/cap_abc123/export \
  -H "Authorization: Bearer poly_a1b2c3d4e5f6..." \
  -H "Content-Type: application/json" \
  -d '{
    "format": "obj"
  }'

Example Request — Floorplan PDF export

curl -X POST https://poly.cam/api/v1/captures/cap_abc123/export \
  -H "Authorization: Bearer poly_a1b2c3d4e5f6..." \
  -H "Content-Type: application/json" \
  -d '{
    "format": "pdf"
  }'

Example Request — Floorplan report CSV export

curl -X POST https://poly.cam/api/v1/captures/cap_abc123/export \
  -H "Authorization: Bearer poly_a1b2c3d4e5f6..." \
  -H "Content-Type: application/json" \
  -d '{
    "format": "report-csv"
  }'

Response 202

{
  "jobId": "550e8400-e29b-41d4-a716-446655440000",
  "status": "pending",
  "exportFormat": "pdf",
  "captureId": "cap_abc123"
}
Asynchronous processing Export conversion runs in the background. Use the returned jobId with GET /v1/exports/:jobId to poll for completion and retrieve the download URL.
Floorplan exports Floorplan formats (png, svg, pdf, dxf, json, report-csv, report-pdf) require the capture to have floorplan data (i.e. the capture mode must be floorplan). The georeference and pointCloudDensity options are not applicable to floorplan exports.

Error Responses

StatusReason
400Invalid JSON body or invalid/missing format
401Missing or invalid API token
404Capture not found or does not belong to your workspace
422Capture has no mesh available for export (mesh formats) or no floorplan data available (floorplan formats)
500Failed to create export job

Get Export Job Status

GET /v1/exports/:jobId API Token

Returns the current status of an export conversion job. When the job completes successfully, the response includes an outputUrl with a download link for the exported file.

Path Parameters

ParameterTypeDescription
jobId string The job ID returned from POST /v1/captures/:captureId/export.

Example Request

curl https://poly.cam/api/v1/exports/550e8400-e29b-41d4-a716-446655440000 \
  -H "Authorization: Bearer poly_a1b2c3d4e5f6..."

Response 200 — Pending/Running

{
  "jobId": "550e8400-e29b-41d4-a716-446655440000",
  "status": "pending",
  "type": "export",
  "exportFormat": "obj",
  "captureId": "cap_abc123",
  "createdAt": 1706140800000
}

Response 200 — Complete

{
  "jobId": "550e8400-e29b-41d4-a716-446655440000",
  "status": "complete",
  "type": "export",
  "exportFormat": "obj",
  "captureId": "cap_abc123",
  "createdAt": 1706140800000,
  "outputUrl": "https://storage.example.com/exports/capture.obj?token=..."
}

Response 200 — Failed

{
  "jobId": "550e8400-e29b-41d4-a716-446655440000",
  "status": "failed",
  "type": "export",
  "exportFormat": "obj",
  "captureId": "cap_abc123",
  "createdAt": 1706140800000,
  "error": "Conversion failed: insufficient mesh data"
}
Job types The type field is "export" for mesh conversion jobs and "floorplan-export" for floorplan conversion jobs.

Job Statuses

StatusDescription
pendingJob is queued and waiting to be processed.
runningJob is currently being processed.
completeJob finished successfully. outputUrl is available.
failedJob failed. error field contains the reason.
Polling recommendation Poll this endpoint every few seconds until status is "complete" or "failed". Export jobs typically complete within a minute.

Error Responses

StatusReason
401Missing or invalid API token
404Export job not found or does not belong to your workspace

Capture Object

Every capture returned by the API has the following shape:

FieldTypeDescription
idstringUnique capture identifier.
namestringDisplay name of the capture.
descriptionstring?Optional description.
tagsstring[]User-assigned tags.
createdAtnumberUnix timestamp (ms) when the capture was created.
updatedAtnumberUnix timestamp (ms) of the last update.
visibilitystringVisibility setting (e.g. "private", "public").
sessionobjectSession metadata — see below.
processingobjectProcessing status and timing — see below.
meshobject?Mesh geometry info (if available).
geoDataobject?Geographic data, if available.
availableArtifactsstring[]List of artifact filenames that exist for this capture.
thumbnailstring?URL to the thumbnail image, if available.
externalIdstring?External reference ID for linking to external systems (max 256 characters). Set via PATCH.

session object

FieldTypeDescription
modestringCapture mode. See Capture Modes.
devicestring?Device used (e.g. "iPhone 15 Pro").
appVersionstring?Polycam app version.
durationnumber?Capture session duration in seconds.
importedboolean?Whether the capture was imported.
droneboolean?Whether the capture was taken with a drone.

processing object

FieldTypeDescription
statusstring"completed" or "pending".
sessionDurationnumber?Session duration in seconds.
processingDurationnumber?Cloud processing time in seconds.
processingVersionstring?Version of the processing pipeline used.
jobobject?Details of the most recent processing job, if one exists — see below.

processing.job object (optional)

Present when the capture has an associated processing job. This is the most reliable way to detect when processing has finished from a webhook payload.

FieldTypeDescription
idstringThe processing job ID.
typestringThe type of processing job.
statusstringJob status, e.g. "pending", "running", "completed", or "failed".
createdAtnumber?Unix timestamp (ms) when the job was created.
finishedAtnumber?Unix timestamp (ms) when the job finished.
errorstring?Failure reason, present when status is "failed".

mesh object (optional)

FieldTypeDescription
vertexCountnumberTotal number of mesh vertices.
faceCountnumberTotal number of mesh faces.
bboxSize[x, y, z]Bounding box dimensions in meters.
bboxCenter[x, y, z]Bounding box center coordinates.

Capture Modes

The session.mode field returns one of the following values:

ModeDescription
lidarLiDAR scan (default for legacy captures).
photoPhotogrammetry capture (photo, object, or objectCapture modes).
floorplanRoomPlan-based floorplan scan.
spaceSpace capture (large-area scanning).
360360° spherical capture.
importImported 3D model or camera upload.
splatGaussian splat capture.
generatedAI-generated 3D model.

Artifacts

The availableArtifacts array lists filenames of data files associated with a capture. These indicate which export formats and data are available.

ArtifactDescription
thumbnail.jpgCapture thumbnail image.
video.mp4Video trailer / flythrough.
edited.gltfEdited glTF mesh (only present if the capture has been edited).
original.gltfOriginal glTF mesh.
edited_geometry.binBinary geometry data for edited.gltf.
original_geometry.binBinary geometry data for original.gltf.
textures/*Texture image files referenced by the glTF meshes (e.g. textures/0.jpg, textures/1.jpg). The exact filenames vary per capture.
skybox.jpgSkybox texture (360° captures).
original_floorplan.jsonOriginal floorplan data (from Apple RoomPlan).
optimized_floorplan.jsonOptimized floorplan data.
edited_floorplan.jsonUser-edited floorplan data.
import.zipOriginal imported file.
edited.splatEdited Gaussian splat (only present if the capture has been edited).
original.splatOriginal unedited Gaussian splat.
splat.plyGaussian splat in PLY format.

Export Formats

The following formats are supported by the export conversion endpoint. Pass one of these values as the format field in the request body.

Mesh Formats

These formats require the capture to have mesh data (3D model).

FormatExtensionDescription
glb.glbGLB — self-contained binary glTF mesh.
obj.objWavefront OBJ — widely supported mesh format.
fbx.fbxAutodesk FBX — common in game engines and 3D tools.
stl.stlSTL — standard for 3D printing.
dae.daeCOLLADA — XML-based interchange format.
usdz.usdzUSDZ — Apple's AR-ready format.
ply.plyPLY — point cloud format. Supports pointCloudDensity and georeference.
las.lasLAS — industry-standard point cloud. Supports pointCloudDensity and georeference.
pts.ptsPTS — point cloud format. Supports pointCloudDensity and georeference.
xyz.xyzXYZ — simple point cloud format. Supports pointCloudDensity and georeference.

Floorplan Formats

These formats require the capture to have floorplan data (i.e. captures made with the floorplan mode). The georeference and pointCloudDensity options are not applicable to floorplan exports.

FormatExtensionDescription
png.pngPNG — rasterized 2D floorplan image.
svg.svgSVG — scalable vector floorplan drawing.
pdf.pdfPDF — printable 2D floorplan document.
dxf.dxfDXF — AutoCAD-compatible floorplan drawing.
json.jsonJSON — structured floorplan data.
report-csv.csvCSV report — tabular room measurements and areas.
report-pdf.pdfPDF report — formatted report with room measurements and areas.

Health Check

GET /v1/health

Simple health check. No authentication required.

curl https://poly.cam/api/v1/health

Response 200

{
  "status": "ok",
  "service": "api-v1"
}
Polycam Content Management API Documentation