API Documentation
Integrate powerful image processing directly into your application. Remove backgrounds and prepare product images for e-commerce with a simple REST API.
Quickstart
Go from zero to your first processed image in under two minutes. OptikAPI speaks plain REST: send multipart/form-data, get back JSON with your image as a Base64 data URL.
Create an account
Sign up for free. Every new account gets 20 trial credits.
Generate an API key
Create a key in the dashboard. Keys are shown once — store them safely.
Make a request
POST an image to an endpoint and get the processed result back.
curl -X POST https://your-domain.com/api/v1/remove-background \
-H "Authorization: Bearer YOUR_API_KEY" \
-F "file=@product.jpg"{
"job_id": "job_9f3a2c1e",
"status": "succeeded",
"output_url": "data:image/png;base64,iVBORw0KGgoAAAANS...",
"reserved_credits": 1
}output_url is a transparent PNG, ready to use. Decode the Base64 payload and save it — or pass it straight to your storefront.Authentication
All API requests are authenticated with a Bearer token. Include your secret API key in the Authorization header of every request.
Authorization: Bearer optk_your_api_key_hereAPI keys start with optk_ and can be created or revoked at any time from the API Keys dashboard. Revoking a key takes effect immediately.
Background Removal
/api/v1/remove-backgroundRemoves the background from an image with high precision — clean edges around hair, glass, and complex shapes. Costs 1 credit per successful image and returns a transparent PNG as a Base64 data URL.
Idempotency-Key header (1–200 visible ASCII characters). Reuse the same key with the same image and service: a completed job returns its saved result without another charge; a running job returns 202 with its job ID andRetry-After. A failed job returns its saved failure; use a new key for a new attempt. Reusing a key with different content or a different service returns 409. Keys belong to your account. Replayed responses include Idempotency-Replayed: true. File contents must match their declared JPEG, PNG, or WebP type. Files are limited to 10 MiB; the whole multipart body is limited to 10 MiB + 64 KiB. Suspended accounts receive 403.Request Body
Format: multipart/form-data
| Parameter | Type | Description |
|---|---|---|
file | File (required) | Source image. Accepted types: JPEG, PNG, WebP. Max size: 10MB. |
Response (200 OK)
| Field | Type | Description |
|---|---|---|
job_id | string | Unique job identifier. Use it with Get Job to retrieve details later. |
status | string | Always "succeeded" on a 200 response. |
output_url | string | Processed image as a Base64 data URL (image/png). |
reserved_credits | number | Credits charged for this job (1). |
Code Examples
curl -X POST https://your-domain.com/api/v1/remove-background \
-H "Authorization: Bearer YOUR_API_KEY" \
-F "file=@/path/to/image.jpg"
# Response (200):
# {
# "job_id": "job_9f3a2c1e",
# "status": "succeeded",
# "output_url": "data:image/png;base64,...",
# "reserved_credits": 1
# }E-commerce Preparation
/api/v1/prepare-productAn all-in-one pipeline: removes the background, centers the product with optical (not geometric) alignment, applies consistent margins, and places it on a clean white canvas. Costs 2 credits per successful image. Output is a 2000×2000 white-background image returned as a Base64 data URL.
Request Body
Format: multipart/form-data
| Parameter | Type | Description |
|---|---|---|
file | File (required) | Source product image. Accepted types: JPEG, PNG, WebP. Max size: 10MB. |
Response (200 OK)
| Field | Type | Description |
|---|---|---|
job_id | string | Unique job identifier. |
status | string | Always "succeeded" on a 200 response. |
output_url | string | Processed 2000×2000 image as a Base64 data URL. |
reserved_credits | number | Credits charged for this job (2). |
The processor returns the prepared image. Product classification, fill ratio, and centering measurements are not included in the response.
Code Examples
curl -X POST https://your-domain.com/api/v1/prepare-product \
-H "Authorization: Bearer YOUR_API_KEY" \
-F "file=@/path/to/product.jpg"
# Response (200):
# {
# "job_id": "job_7b1d4e8a",
# "status": "succeeded",
# "output_url": "data:image/png;base64,...",
# "reserved_credits": 2
# }Get Credits
/api/v1/creditsReturns the current credit balance of the authenticated account. Use it to monitor usage and trigger alerts before you run out.
curl https://your-domain.com/api/v1/credits \
-H "Authorization: Bearer YOUR_API_KEY"
# Response (200):
# {
# "credits": {
# "total": 500,
# "available": 492,
# "reserved": 8
# }
# }| Field | Type | Description |
|---|---|---|
credits.total | number | Total credits ever purchased or granted. |
credits.available | number | Credits you can spend right now. |
credits.reserved | number | Credits temporarily locked by in-flight jobs. |
Get Job
/api/v1/jobs/:job_idRetrieves the status and result of a job by its ID. Image endpoints are synchronous — they return the final image immediately — so this endpoint is mainly useful for auditing, debugging, and checking a request that is still processing.
curl https://your-domain.com/api/v1/jobs/job_7b1d4e8a \
-H "Authorization: Bearer YOUR_API_KEY"
# Response (200):
# {
# "job_id": "job_7b1d4e8a",
# "status": "succeeded",
# "service_type": "prepare-product",
# "created_at": "2026-09-19T10:24:11.000Z",
# "output_url": "data:image/png;base64,...",
# "credits_consumed": 2
# }| Field | Type | Description |
|---|---|---|
job_id | string | Job identifier. |
status | string | "accepted", "processing", "succeeded", or "failed". |
service_type | string | "remove-background" or "prepare-product". |
created_at | string | ISO 8601 creation timestamp. |
output_url | string | Result data URL. Present only when status is "succeeded". |
credits_consumed | number | Credits charged. Present only when status is "succeeded". |
error | string | Failure reason. Present only when status is "failed". |
404 NOT_FOUND, as does an unknown ID.Limits & Queue
Rate limits
The API allows 300 requests per minute per account across all /api/v1/* endpoints. Exceeding it returns 429 RATE_LIMITED with a Retry-After header telling you exactly when to try again.
Fair-use concurrency queue
Each account may run up to 3 image jobs concurrently. Requests beyond that wait in a FIFO line for up to ~20 seconds instead of failing, which makes bursty catalog imports work smoothly without any client-side throttling.
If the waiting line is full or a request waits too long, the API responds with 429 and one of two error codes — always with a Retry-After header:
| Code | Meaning | What to do |
|---|---|---|
QUEUE_FULL | The waiting line for your account is full. | Back off and retry after the Retry-After seconds. |
QUEUE_TIMEOUT | Your request waited ~20s without getting a slot. | Retry; reduce burst size or add a short delay between requests. |
Error Codes
OptikAPI uses standard HTTP status codes. Every error response has the same shape — a machine-readable code and a human-readable message:
{
"error": {
"code": "PAYMENT_REQUIRED",
"message": "Insufficient credits"
}
}| Status | Code | Description |
|---|---|---|
| 400 | BAD_REQUEST | Missing required parameter (usually the file field). |
| 401 | UNAUTHORIZED | Missing or invalid API key. |
| 402 | PAYMENT_REQUIRED | Insufficient credits for the requested operation. |
| 403 | FORBIDDEN | The job belongs to a different account. |
| 404 | NOT_FOUND | Job not found. |
| 413 | PAYLOAD_TOO_LARGE | Uploaded image exceeds the 10MB limit. |
| 422 | UNSUPPORTED_MEDIA_TYPE | File type not supported. Use JPEG, PNG, or WebP. |
| 429 | RATE_LIMITED, QUEUE_FULL, QUEUE_TIMEOUT | Too many requests or concurrency slots busy. Respect the Retry-After header. |
| 500 | INTERNAL_SERVER_ERROR | Processing failed on our side. Credits are refunded; retry with exponential backoff. |
Best Practices
Retrying safely
- On
429, always wait at least theRetry-Afterseconds before retrying. - On
500and network errors, use exponential backoff with jitter (e.g. 1s, 2s, 4s, 8s — max 5 attempts). - Never retry
400,401,402,413, or422without fixing the request first.
async function processWithRetry(form, attempt = 0) {
const res = await fetch('https://your-domain.com/api/v1/remove-background', {
method: 'POST',
headers: { 'Authorization': 'Bearer YOUR_API_KEY' },
body: form,
});
if (res.ok) return res.json();
const retryable = res.status === 429 || res.status >= 500;
if (retryable && attempt < 5) {
const retryAfter = Number(res.headers.get('retry-after') || 0);
const backoff = Math.min(2 ** attempt + Math.random(), 30);
await new Promise(r => setTimeout(r, Math.max(retryAfter, backoff) * 1000));
return processWithRetry(form, attempt + 1);
}
const { error } = await res.json();
throw new Error(`${error.code}: ${error.message}`);
}Working with Base64 output
- Split on the first comma only:
output_url.split(",")[1]— never strip thedata:image/png;base64,prefix with fixed string lengths. - For large batches, stream results to disk or object storage instead of holding them in memory.
Getting the best results
- Use the highest-resolution source you have (the model handles up to 10MB comfortably).
- Well-lit products with clear contrast against their background produce the cleanest edges.
- For catalog work, always use
prepare-product— consistent 2000×2000 canvases make listings look uniform.
API Changelog
We announce new endpoints, behavior changes, and deprecations on the public changelog before they go live.