Integrate Lumely AI into your workflow programmatically.
https://lumely.ai/api/v1All API requests require authentication. There are three supported methods, evaluated in this priority order:
Pass your API key in the Authorization header. Keys are prefixed with lum_live_.
curl -H "Authorization: Bearer lum_live_abc123..." \
https://lumely.ai/api/v1/creditsUse a Supabase session JWT for browser-based integrations.
curl -H "Authorization: Bearer eyJhbGci..." \
https://lumely.ai/api/v1/creditsAutomatically used when calling from the Lumely dashboard. No additional setup needed.
X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset) are included in every response.Check your current credit balance and subscription status.
/api/v1/credits{
"credits_remaining": 58,
"credits_total": 60,
"plan_id": "basic",
"subscription_status": "active",
// Enterprise accounts also receive:
"enterprise": {
"company_name": "Acme Architecture",
"credit_price_cents": 25,
"currency": "EUR",
"auto_topup_enabled": true,
"monthly_credit_limit": 1000,
"credits_used_this_month": 142,
"rate_limit_rpm": 120,
"allowed_services": ["render-enhancement", "virtual-staging"]
}
}List available services and their configuration options.
/api/v1/services{
"services": [
{
"id": "render-enhancement",
"name": "Render Enhancement",
"description": "Enhance architectural renders with photorealistic lighting, materials, and detail.",
"credits_2k": 2,
"credits_4k": 3,
"config_ids": [
"exterior-modern", "exterior-traditional",
"interior-modern", "interior-traditional",
"interior-minimalist", "landscape", "aerial"
],
"supports_mask": true,
"supports_reference_image": false,
"supports_prompt": true
},
{
"id": "virtual-staging",
"name": "Virtual Staging",
"config_ids": ["living-room", "bedroom", "kitchen", "dining-room", "office", "bathroom"],
"supports_mask": true,
"supports_reference_image": true,
"supports_prompt": true
}
// ... more services
],
"resolutions": ["2K", "4K"],
"note": "4K resolution requires a paid subscription."
}| Service | Config IDs | Credits (2K / 4K) | Features |
|---|---|---|---|
| render-enhancement | exterior-modern, exterior-traditional, interior-modern, interior-traditional, interior-minimalist, landscape, aerial | 2 / 3 | Mask, Prompt |
| virtual-staging | living-room, bedroom, kitchen, dining-room, office, bathroom | 2 / 3 | Mask, Reference Image, Prompt |
| design-options | exterior-modern, exterior-traditional, interior-modern, interior-traditional, landscape | 2 / 3 | Mask, Reference Image, Prompt |
| 3d-plans | residential, commercial, office | 2 / 3 | Prompt |
Upload an image to receive a storage_path for use when creating jobs.
/api/v1/upload| Parameter | Type | Required | Description |
|---|---|---|---|
| image | string | Required | Base64-encoded image data, with or without the data:image/... prefix. Supports JPEG, PNG, WebP, and GIF. Max 10 MB body size. |
curl -X POST https://lumely.ai/api/v1/upload \
-H "Authorization: Bearer lum_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"image": "data:image/jpeg;base64,/9j/4AAQ..."
}'Create, list, cancel, and retry image processing jobs. Jobs are processed asynchronously — poll the job status or use webhooks for notifications.
/api/v1/jobs| Parameter | Type | Required | Description |
|---|---|---|---|
| service_type | string | Required | Service to run. One of: render-enhancement, virtual-staging, design-options, 3d-plans. |
| config_id | string | Required | Configuration preset. Valid IDs depend on the service — see the Services table. |
| storage_path | string | Required | Path returned from POST /api/v1/upload. |
| resolution | string | Optional | Output resolution. "2K" (default) or "4K" (paid plans only, costs 3 credits). |
| prompt | string | Optional | Optional text prompt to guide the AI generation. |
| mask_base64 | string | Optional | Base64-encoded mask image for targeted edits (services that support masking). |
| reference_image_base64 | string | Optional | Base64-encoded style reference image (services that support reference images). |
| reference_image_storage_path | string | Optional | Storage path for a previously uploaded reference image (alternative to base64). |
| reference_id | string | Optional | Your own identifier to link this job to your system (max 255 chars). |
| idempotency_key | string | Optional | Unique key to prevent duplicate job creation on retries (max 255 chars). |
| options | object | Optional | Scene settings object: { lighting, weather, season, crowd, camera, style, flooring, landscaping }. |
| location | object | Optional | Geographic location to match local architectural styles. Object: { description, city, region, country, latitude, longitude }. |
curl -X POST https://lumely.ai/api/v1/jobs \
-H "Authorization: Bearer lum_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"service_type": "virtual-staging",
"config_id": "living-room",
"storage_path": "user-uuid/api_1709654321_a1b2c3d4e5f6.jpg",
"resolution": "2K",
"prompt": "Modern Scandinavian style with warm lighting",
"reference_id": "project-42-room-3",
"options": {
"lighting": "warm",
"style": "modern"
},
"location": {
"description": "Grafton Street, Dublin, Ireland",
"city": "Dublin",
"region": "County Dublin",
"country": "Ireland",
"latitude": 53.3411,
"longitude": -6.2603
}
}'/api/v1/jobs/{job_id}| Status | Description |
|---|---|
| pending | Job is queued and waiting to be processed. |
| compressing | Input image is being optimised for processing. |
| processing | AI generation is in progress (typically 30–90 seconds). |
| completed | Job finished successfully. Output URL is available. |
| failed | Processing encountered an error. Check error_message. Can be retried. |
| cancelled | Job was cancelled by the user. Can be retried. |
/api/v1/jobs| Parameter | Type | Required | Description |
|---|---|---|---|
| status | string | Optional | Filter by job status (e.g. completed, failed). |
| service_type | string | Optional | Filter by service type. |
| limit | integer | Optional | Number of results (default: 50, max: 100). |
| offset | integer | Optional | Pagination offset (default: 0). |
/api/v1/jobs/{job_id}| Parameter | Type | Required | Description |
|---|---|---|---|
| action | string | Required | "cancel" (pending/processing jobs) or "retry" (failed/cancelled jobs). Credits are re-validated on retry. |
Create and manage API keys. You can have up to 10 active keys.
/api/v1/api-keys/api/v1/api-keys| Parameter | Type | Required | Description |
|---|---|---|---|
| name | string | Optional | Label for the key (default: "Default", max 100 chars). |
/api/v1/api-keys/{key_id}/api/v1/api-keys/{key_id}| Parameter | Type | Required | Description |
|---|---|---|---|
| name | string | Optional | PATCH only. Update the key label. |
| is_active | boolean | Optional | PATCH only. Set false to revoke, true to re-activate. |
Receive real-time notifications when jobs complete, fail, or are cancelled. You can register up to 5 active webhook endpoints.
/api/v1/webhooks| Parameter | Type | Required | Description |
|---|---|---|---|
| url | string | Required | HTTPS URL to receive webhook POST requests. Localhost allowed for testing. |
| events | string[] | Optional | Events to subscribe to. Default: ["job.completed", "job.failed"]. Available: job.completed, job.failed, job.cancelled. |
/api/v1/webhooks/{webhook_id}/api/v1/webhooks/{webhook_id}| Parameter | Type | Required | Description |
|---|---|---|---|
| url | string | Optional | PATCH only. New HTTPS URL. |
| events | string[] | Optional | PATCH only. Updated event subscriptions. |
| is_active | boolean | Optional | PATCH only. Set false to deactivate, true to re-enable (resets failure count). |
/api/v1/webhooksEach webhook delivery includes a signature in the X-Lumely-Signature header. Verify it using your webhook secret to ensure the request came from Lumely.
const crypto = require('crypto');
function verifyWebhookSignature(payload, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(JSON.stringify(payload))
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
// In your webhook handler:
app.post('/webhooks/lumely', (req, res) => {
const signature = req.headers['x-lumely-signature'];
if (!verifyWebhookSignature(req.body, signature, WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
const { event, data } = req.body;
if (event === 'job.completed') {
console.log('Output:', data.output_image_url);
}
res.status(200).send('OK');
});All errors return a JSON object with an error field and usually a message field with actionable guidance.
{
"error": "Insufficient credits",
"message": "You need 2 credits but only have 1 remaining.",
"credits_required": 2,
"credits_remaining": 1
}| Code | Meaning | Common Causes |
|---|---|---|
| 200 | OK | Successful read, update, cancel, or retry. |
| 201 | Created | Successfully created a resource (job, API key, webhook, upload). |
| 400 | Bad Request | Missing required fields, invalid service_type, invalid config_id, malformed image data. |
| 401 | Unauthorised | Invalid or revoked API key, expired Bearer token, no auth provided. |
| 403 | Forbidden | Insufficient credits, 4K without paid plan, storage path access denied, monthly limit reached. |
| 404 | Not Found | Job/key/webhook ID not found or belongs to another account, no subscription. |
| 405 | Method Not Allowed | HTTP method not supported for this endpoint. Check the "allowed" array in the response. |
| 409 | Conflict | Duplicate job detected (when using idempotency_key — existing job returned with 200 instead). |
| 429 | Rate Limited | Too many requests. Check Retry-After header and X-RateLimit-* headers. |
| 500 | Server Error | Internal error. The response message will suggest whether to retry. |
Every response includes these headers:
| Header | Description |
|---|---|
| X-RateLimit-Limit | Maximum requests allowed per minute. |
| X-RateLimit-Remaining | Requests remaining in the current window. |
| X-RateLimit-Reset | ISO 8601 timestamp when the limit resets. |
| Retry-After | Seconds to wait before retrying (only present on 429 responses). |
Here's the full flow to enhance an image via the API:
Step 1: Upload your image
curl -X POST https://lumely.ai/api/v1/upload \
-H "Authorization: Bearer lum_live_abc123..." \
-H "Content-Type: application/json" \
-d '{ "image": "data:image/jpeg;base64,/9j/4AAQ..." }'
# Response: { "storage_path": "user-uuid/api_123_abc.jpg", ... }Step 2: Create a job
curl -X POST https://lumely.ai/api/v1/jobs \
-H "Authorization: Bearer lum_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"service_type": "render-enhancement",
"config_id": "exterior-modern",
"storage_path": "user-uuid/api_123_abc.jpg"
}'
# Response: { "id": "JOB_ID", "status": "pending", "poll_url": "/api/v1/jobs/JOB_ID" }Step 3: Poll for completion (or use webhooks)
curl https://lumely.ai/api/v1/jobs/JOB_ID \
-H "Authorization: Bearer lum_live_abc123..."
# When status is "completed":
# { "status": "completed", "output_image_url": "https://..." }Step 4: Download the result
# The output_image_url is a public URL — download directly:
curl -o result.jpg "https://your-supabase-url.../output-image.jpg"Need help with your integration?