2D to 3D Generator — API Reference
Base URL: https://api.wearfits.com
Interactive documentation: - OpenAPI Spec: api.wearfits.com/doc - Swagger UI: api.wearfits.com/reference - Shoe AR Integration Guide: tryon.wearfits.com/docs/integration-shoes
Authentication
All /api/* routes require the X-API-Key header. API keys are created and managed at dash.wearfits.com.
Requests without a valid key return HTTP 401.
Browser-based WEARFITS flows also protect shoe generation, file upload, and job requests with Turnstile verification. The hosted application manages this automatically: successful verification sets a signed, HttpOnly pass cookie bound to the browser's network. The pass is valid for a fixed one hour from verification (use does not extend it) and can authorize later protected requests from that same network without another Turnstile check. A request with a Turnstile token uses that token and can mint a fresh pass; if a pass expires or is rejected, the application retries with fresh verification. Keep cookies enabled for these flows. Protected responses expose the remaining pass lifetime in X-Wearfits-Verification-TTL; a browser-protected request with neither a valid token nor pass returns HTTP 403. The verification pass does not replace X-API-Key for direct API integrations.
Image Input Formats
All images fields across the API accept two formats:
- URLs (HTTP/HTTPS) — standard web URLs pointing to publicly accessible hosted images.
- Base64 Data URLs — inline base64-encoded images embedded directly in the request body.
- Format:
data:image/<format>;base64,<data> - Supported image formats:
png,jpeg,jpg,gif,webp,svg+xml
Endpoints
POST /api/v1/shoe-3d
Generate a high-quality 3D shoe model from one or more 2D product photos. The request is accepted immediately and processed asynchronously. Use GET /api/v1/jobs/{jobId} to poll for results.
Returns: 202 Accepted with a jobId.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
images |
string[] |
Yes | List of shoe photo URLs or base64 data URLs. Provide multiple angles for best results. |
glbInput |
string |
No | URL to an existing GLB file to use as the base for transformation or texture enhancement instead of generating from scratch. |
options |
object |
No | Processing options (see below). |
options.uploadToWearFits |
boolean |
No | After generation, automatically upload the model to the AR platform at dev.wearfits.com. |
options.sessionId |
string |
No | Optional WEARFITS session identifier for ownership. When supplied, it takes precedence over the account associated with the API credential and is the only ownership claim used for the upload. |
options.enhanceTexture |
boolean |
No | Run an AI texture enhancement pass after 3D generation. Renders multiple views, enhances them with Gemini, then projects the result back onto the model. |
options.correctImage |
boolean |
No | Apply professional packshot correction to the input photos before 3D generation. |
options.productType |
string |
No | Hint for the generation model. One of: shoe, other, or auto (default). |
options.refineLogo |
boolean |
No | Run a second AI pass focused specifically on fixing logos and brand text on the generated model. Non-fatal: if the logo pass fails, the pipeline continues with first-pass results. |
options.genaiQuality |
string |
No | Controls texture enhancement quality and render count. "default" uses 4 views (3-minute timeout). "high" uses 6 views (5-minute timeout). Defaults to "high" when enhanceTexture is enabled. |
Who the uploaded model belongs to
When options.uploadToWearFits is true, the generated model is assigned to exactly one WEARFITS owner:
- The account associated with the API credential (automatic). If the credential resolves to a WEARFITS account, that account's library receives the model. No additional field is required.
options.sessionId(explicit). Use this when your frontend already has a WEARFITS user session and the model should be linked to that session.
options.sessionId takes precedence. When it is present, it is the only ownership claim used for the upload; the account associated with the credential is not used. Do not provide conflicting ownership claims.
If neither an account association nor a session is available, the model is placed in the integration's default WEARFITS library rather than linked to an individual session.
Example request
curl -X POST https://api.wearfits.com/api/v1/shoe-3d \
-H "X-API-Key: your_api_key" \
-H "Content-Type: application/json" \
-d '{
"images": [
"https://example.com/shoe-side.jpg",
"https://example.com/shoe-front.jpg",
"https://example.com/shoe-back.jpg"
],
"options": {
"uploadToWearFits": true,
"enhanceTexture": true,
"correctImage": true,
"productType": "shoe",
"refineLogo": false,
"genaiQuality": "high"
}
}'
Example request with base64 image
curl -X POST https://api.wearfits.com/api/v1/shoe-3d \
-H "X-API-Key: your_api_key" \
-H "Content-Type: application/json" \
-d '{
"images": [
"data:image/jpeg;base64,/9j/4AAQSkZJRgAB..."
],
"options": {
"productType": "shoe"
}
}'
Example request with existing GLB
curl -X POST https://api.wearfits.com/api/v1/shoe-3d \
-H "X-API-Key: your_api_key" \
-H "Content-Type: application/json" \
-d '{
"images": [
"https://example.com/shoe-packshot.jpg"
],
"glbInput": "https://example.com/base-model.glb",
"options": {
"enhanceTexture": true,
"uploadToWearFits": true
}
}'
WEARFITS upload limit and related errors
When options.uploadToWearFits is enabled, the final GLB uploaded to WEARFITS must be no larger than 20 MB. The service attempts to compress oversized output before uploading it. If the result still exceeds the limit, the job fails instead of uploading the model. Use a smaller or simpler source model, or disable the WEARFITS upload.
Upload failures use these codes:
| Code | Meaning | Recommended action |
|---|---|---|
attribution_unavailable |
WEARFITS temporarily could not resolve the attributed account. | Retry the request or job after the temporary service issue clears. |
invalid_user_id |
The supplied session or account owner identifier is not valid. | Correct the ownership value and submit a new job. |
attribution_conflict |
The upload contains conflicting ownership claims. | Use one ownership method; options.sessionId takes precedence when supplied. |
file_too_large |
The final GLB remains above the 20 MB WEARFITS upload ceiling after compression. | Use a smaller or simpler model, or omit uploadToWearFits. |
Response — 202 Accepted
POST /api/v1/files/upload
Upload a large binary file (such as a source .glb model) to Cloudflare R2 storage before triggering the shoe-3d pipeline. Use this endpoint when your GLB exceeds the inline payload size limit for the shoe-3d request body.
The endpoint returns a hosted URL that can be passed as glbInput in a subsequent POST /api/v1/shoe-3d call.
Request
Content-Type: multipart/form-data
| Field | Type | Required | Description |
|---|---|---|---|
file |
file | Yes | The binary file to upload (e.g., .glb). |
Example request
curl -X POST https://api.wearfits.com/api/v1/files/upload \
-H "X-API-Key: your_api_key" \
-F "[email protected]"
Response — 200 OK
Use the returned url as the glbInput value when calling POST /api/v1/shoe-3d.
GET /api/v1/jobs/{jobId}
Poll the status and retrieve the final results of an asynchronous job submitted via POST /api/v1/shoe-3d or any other job-producing endpoint. Responses include Cache-Control: no-store; the hosted application proxy preserves this header, so do not cache job-status responses. Proxied responses also include X-Content-Type-Options: nosniff. These headers prevent browser/intermediary cache reuse and MIME sniffing, although a newly written status may still take a short time to become visible.
Some non-shoe job types expose lifecycle stages without measured provider progress. For virtual-fitting and digital-twin, progress.percentage is absent until completion, when it is 100; render an indeterminate spinner while it is absent.
Path parameters
| Parameter | Type | Description |
|---|---|---|
jobId |
string |
Job identifier returned by the submission endpoint. |
Example request
curl https://api.wearfits.com/api/v1/jobs/job_01HX3Z7K2MFVBN9Q4RPTDY6WCE \
-H "X-API-Key: your_api_key"
Response — 200 OK (in progress)
Response — 200 OK (completed)
{
"jobId": "job_01HX3Z7K2MFVBN9Q4RPTDY6WCE",
"status": "completed",
"progress": 100,
"result": {
"glbUrl": "https://storage.example.com/models/shoe.glb",
"viewerUrl": "https://app.wearfits.com/viewer?object=abc123",
"previewGrid": "https://storage.example.com/previews/shoe-grid.png"
}
}
Response — 200 OK (failed)
{
"jobId": "job_01HX3Z7K2MFVBN9Q4RPTDY6WCE",
"status": "failed",
"error": "Generation failed: no valid shoe silhouette detected in input images."
}
Job status values
| Status | Description |
|---|---|
queued |
Job has been accepted and is waiting for a processing slot. |
validating |
Input images and parameters are being validated. |
processing |
3D generation and optional AI passes are running. |
uploading |
Generated model is being uploaded to storage and, if requested, to the AR platform. |
completed |
Processing is complete. The result object contains output URLs. |
failed |
An unrecoverable error occurred. See the error field for details. |
Result fields (on completion)
| Field | Description |
|---|---|
glbUrl |
Direct URL to the generated GLB 3D model file. |
viewerUrl |
URL to preview the model in the WEARFITS 3D viewer. |
previewGrid |
URL to a composite preview image showing the model from multiple angles. |
Recommended polling interval
Poll every 5–10 seconds. Typical processing times are 2–5 minutes depending on enabled options and queue depth. Do not poll more frequently than every 2 seconds to stay within rate limits.
DELETE /api/v1/jobs/{jobId}
Cancel a running job. The job is terminated immediately. Jobs that have already reached completed or failed status cannot be cancelled.
Path parameters
| Parameter | Type | Description |
|---|---|---|
jobId |
string |
Job identifier to cancel. |
Example request
curl -X DELETE https://api.wearfits.com/api/v1/jobs/job_01HX3Z7K2MFVBN9Q4RPTDY6WCE \
-H "X-API-Key: your_api_key"
Response — 200 OK
POST /api/v1/digitization/batches
Submit multiple shoes for bulk 3D digitization processing. This is a secondary endpoint intended for high-volume batch workflows. Jobs submitted via this endpoint are placed in a lower-priority queue (DIGITIZATION_QUEUE) separate from the real-time JOB_QUEUE used by POST /api/v1/shoe-3d.
Example request
curl -X POST https://api.wearfits.com/api/v1/digitization/batches \
-H "X-API-Key: your_api_key" \
-H "Content-Type: application/json" \
-d '{
"items": [
{
"images": ["https://example.com/shoe-a-side.jpg"],
"options": { "productType": "shoe", "uploadToWearFits": true }
},
{
"images": ["https://example.com/shoe-b-side.jpg"],
"options": { "productType": "shoe", "uploadToWearFits": true }
}
]
}'
Use GET /api/v1/jobs/{jobId} to track each item's progress individually.
Webhook Signatures
If your integration is configured to receive webhook notifications, each webhook payload is signed with HMAC-SHA256 using a secret derived from your API key.
Signing secret: SHA-256(your_api_key) (hex-encoded string).
Verification steps
-
Compute the signing secret:
-
Sort the webhook JSON body keys alphabetically and serialize to a canonical string:
-
Compute the HMAC-SHA256 of the canonical string using the signing secret:
-
Compare the computed signature with the value in the
X-Webhook-Signaturerequest header. Use a constant-time comparison to avoid timing attacks:
Rate Limits
Limits apply per API key per minute.
| Endpoint category | Limit |
|---|---|
| Job submission (POST) | 50 requests/min |
| Job status (GET) | 500 requests/min |
| File downloads | 300 requests/min |
| Health check | 5000 requests/min |
Requests that exceed the limit return HTTP 429 Too Many Requests.
Note: Rate limits are 10x higher when using
localhostor the development API key (DEV_API_KEY). This elevated limit applies to local development environments only and is not active in production.
Full Integration Example
The following example demonstrates a complete shoe-3d workflow: uploading a large GLB base file, submitting the generation job, polling until completion, and handling the result.
# Step 1: Upload a large base GLB (if applicable)
UPLOAD_RESPONSE=$(curl -s -X POST https://api.wearfits.com/api/v1/files/upload \
-H "X-API-Key: your_api_key" \
-F "[email protected]")
GLB_URL=$(echo $UPLOAD_RESPONSE | jq -r '.url')
# Step 2: Submit the shoe-3d generation job
JOB_RESPONSE=$(curl -s -X POST https://api.wearfits.com/api/v1/shoe-3d \
-H "X-API-Key: your_api_key" \
-H "Content-Type: application/json" \
-d "{
\"images\": [\"https://example.com/shoe-side.jpg\"],
\"glbInput\": \"$GLB_URL\",
\"options\": {
\"uploadToWearFits\": true,
\"enhanceTexture\": true,
\"genaiQuality\": \"high\"
}
}")
JOB_ID=$(echo $JOB_RESPONSE | jq -r '.jobId')
echo "Job submitted: $JOB_ID"
# Step 3: Poll for job completion
while true; do
STATUS_RESPONSE=$(curl -s "https://api.wearfits.com/api/v1/jobs/$JOB_ID" \
-H "X-API-Key: your_api_key")
STATUS=$(echo $STATUS_RESPONSE | jq -r '.status')
PROGRESS=$(echo $STATUS_RESPONSE | jq -r '.progress')
echo "Status: $STATUS ($PROGRESS%)"
if [ "$STATUS" = "completed" ]; then
GLB_URL=$(echo $STATUS_RESPONSE | jq -r '.result.glbUrl')
VIEWER_URL=$(echo $STATUS_RESPONSE | jq -r '.result.viewerUrl')
echo "Done! GLB: $GLB_URL"
echo "Viewer: $VIEWER_URL"
break
elif [ "$STATUS" = "failed" ]; then
ERROR=$(echo $STATUS_RESPONSE | jq -r '.error')
echo "Job failed: $ERROR"
break
fi
sleep 10
done