API Documentation
PhotoFig API
Queue product image edits, upload source files, poll job status, and receive webhook events with API keys.
Need a machine-readable schema? Download the OpenAPI JSON.
On this page
export PHOTOFIG_API_KEY="pf_live_..."
JOB_ID=$(curl -s -X POST https://api.photofig.com/v1/tools/ai-shadows/edit \
-H "Authorization: Bearer $PHOTOFIG_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"imageUrl": "https://cdn.example.com/product.png",
"parameters": { "seed": 128742 }
}' | jq -r '.id')
curl -L "$(curl -s -H "Authorization: Bearer $PHOTOFIG_API_KEY" \
"https://api.photofig.com/v1/jobs/$JOB_ID" \
| tee /dev/stderr \
| jq -r '.resultUrl')" \
-o ./photofig-result.pngAuthentication
API routes accept API keys generated from Settings. The full secret is shown only once when the key is created.
Authorization: Bearer pf_live_...Account
/v1/accountUse this route as a credential smoke test and to inspect plan limits, remaining credits, and available tools.
{
"accountId": "uuid",
"workspaceId": "uuid",
"plan": "pro",
"apiEnabled": true,
"credits": {
"remaining": 1200,
"periodEndsAt": "2026-08-01T00:00:00Z"
},
"limits": {
"maxFileSizeBytes": 25000000,
"rateLimitPerHour": 500,
"concurrentJobs": 5,
"maxApiKeys": 3
},
"tools": ["mask", "ai-bg", "ai-shadows"]
}Tools
/v1/tools/v1/tools/{tool_id}Each tool accepts a normal product image through imageUrl, uploadSessionId, or multipart upload. You do not need to call mask first unless you specifically want a transparent cutout.
mask
Removes the background and returns a PNG subject cutout with transparency. Use it when you need the product isolated for your own compositing or marketplace workflow.
ai-shadows
Adds a realistic product shadow and returns an image ready to place on a clean background. Works best on product photos where the subject is clearly visible and not hidden by a busy scene.
ai-bg
Generates a new product background from a short theme, such as warm oak tabletop or minimal white studio. Submit the product image directly; a separate background-removal call is not required.
Upload and Edit in One Call
/v1/tools/{tool_id}/editThis is the simplest path: submit an edit with an imageUrl when the source image is already reachable by URL, or send a multipart image field for a quick local-file request. It is best when you only need to run one tool against one input.
Choose this when you have one image, one edit, and no need to reuse the uploaded source.
curl -X POST https://api.photofig.com/v1/tools/ai-shadows/edit \
-H "Authorization: Bearer pf_live_..." \
-F "[email protected]" \
-F "seed=128742"Upload First, Edit Later
/v1/uploadsCreate an upload session when the source is a larger local file, or when you want to run more than one tool against the same input. The image bytes go straight to storage once; later edit requests only send the returned uploadSessionId.
Choose this when upload size matters, or when the same source image will feed multiple tools or retries.
UPLOAD_JSON=$(curl -s -X POST https://api.photofig.com/v1/uploads \
-H "Authorization: Bearer pf_live_..." \
-H "Content-Type: application/json" \
-d '{
"contentType": "image/jpeg",
"filename": "product.jpg",
"sizeBytes": 1842031
}')
curl -X PUT "$(echo "$UPLOAD_JSON" | jq -r '.uploadUrl')" \
-H "Content-Type: image/jpeg" \
--data-binary @product.jpg
curl -X POST https://api.photofig.com/v1/tools/ai-shadows/edit \
-H "Authorization: Bearer pf_live_..." \
-H "Content-Type: application/json" \
-d "{
\"uploadSessionId\": \"$(echo "$UPLOAD_JSON" | jq -r '.uploadSessionId')\",
\"parameters\": { \"seed\": 128742 }
}"Create Edits
/v1/tools/{tool_id}/editSubmit edits with imageUrl, uploadSessionId, or multipart field image. The response returns a job ID you can use for polling, cancellation, deletion, and webhook correlation.
AI Background
The AI background endpoint works best with a concise scene theme: a setting, surface, lighting cue, or mood in a few words. Good examples include warm oak tabletop,minimal white studio, and soft morning kitchen light.
curl -X POST https://api.photofig.com/v1/tools/ai-bg/edit \
-H "Authorization: Bearer pf_live_..." \
-H "Content-Type: application/json" \
-d '{
"imageUrl": "https://cdn.example.com/product.png",
"parameters": {
"theme": "warm oak tabletop",
"seed": 128742
}
}'Product Shadow
curl -X POST https://api.photofig.com/v1/tools/ai-shadows/edit \
-H "Authorization: Bearer pf_live_..." \
-H "Content-Type: application/json" \
-d '{
"imageUrl": "https://cdn.example.com/product.png",
"parameters": { "seed": 128742 }
}'Mask
curl -X POST https://api.photofig.com/v1/tools/mask/edit \
-H "Authorization: Bearer pf_live_..." \
-H "Content-Type: application/json" \
-d '{
"imageUrl": "https://cdn.example.com/product.png",
"parameters": { "mode": "standard" }
}'Jobs
/v1/jobs/v1/jobs/{id}/v1/jobs/{id}/cancel/v1/jobs/{id}List, poll, cancel, or delete API jobs. API jobs do not appear in logged-in Uploads or Designs, but deletion removes API-owned artifacts.
GET /v1/jobs/{id} returns JSON status metadata. When processing is complete, download the image from resultUrl. Polling is the simplest integration path; webhooks are better when your backend should be notified automatically.
{
"id": "api_edit_uuid",
"tool": "ai-shadows",
"status": "completed",
"createdAt": "2026-07-15T10:15:00Z",
"startedAt": "2026-07-15T10:15:04Z",
"finishedAt": "2026-07-15T10:15:23Z",
"statusUrl": "https://api.photofig.com/v1/jobs/api_edit_uuid",
"resultUrl": "https://storage.example.com/signed-result-url",
"thumbnailUrl": "https://storage.example.com/signed-thumbnail-url",
"expiresAt": "2026-07-15T11:15:23Z",
"error": null
}Webhooks
Webhooks are callbacks from PhotoFig to your server. Register an HTTPS URL, and PhotoFig sends a request when an API job finishes, fails, or is cancelled. This lets your backend react immediately instead of polling GET /v1/jobs/{id} until the status changes.
/v1/webhooks/v1/webhooks/v1/webhooks/{webhook_id}/v1/webhooks/{webhook_id}/v1/webhooks/{webhook_id}/testSupported events are webhook.test,job.completed,job.failed, and job.cancelled. Event payloads use the same job ID returned when the edit is created.
{
"event": "job.completed",
"eventId": "uuid",
"createdAt": "2026-07-15T10:15:23Z",
"data": {
"id": "api_edit_uuid",
"tool": "ai-shadows",
"status": "completed",
"resultUrl": "https://storage.example.com/signed-result-url",
"thumbnailUrl": "https://storage.example.com/signed-thumbnail-url"
}
}Errors
Error responses use a stable machine-readable code and a human-readable message. Treat the code as the value to branch on in client logic.
{
"code": "invalid_request",
"message": "imageUrl or uploadSessionId is required"
}Result Lifecycle
Completed API jobs stay visible through GET /v1/jobs and GET /v1/jobs/{id}. The status response contains signed resultUrl and thumbnailUrl links when outputs are available.
API artifacts are stored separately from interactive uploads and designs. They are not shown in the app library.
API job records and API-owned input, result, and thumbnail files are retained for 1 hour after the job reaches completed, failed, or cancelled. The expiresAt field shows the scheduled cleanup time for finished jobs.
Use DELETE /v1/jobs/{id} after downloading results you no longer need. It cancels unfinished work when possible and deletes the job record plus API-owned artifacts before the automatic cleanup window.