مستندات API اوپتیپیک
با چند خط کد، هر تصویر را از طریق آدرس یا آپلود مستقیم بفرستید و نسخهی بهینهشده را پس بگیرید — همان موتوری که پلاگین وردپرس و ابزار داخل سایت هم روی آن سوار هستند.
معرفی
API اوپتیپیک یک واسط REST ساده و مبتنی بر JSON است. یک تصویر (بهصورت فایل یا آدرس) میفرستید، یک شناسهی job پس میگیرید، وضعیتش را پیگیری میکنید و وقتی آماده شد دانلودش میکنید. برای پردازش چند تصویر با هم، از حالت دستهای (batch) استفاده کنید.
آدرس پایه
همهی درخواستهای این API به آدرس زیر ارسال میشوند — این هم یک لایهی واسط است، نه بکاند پردازشی خام؛ صرفاً روی زیردامنهی مخصوص API میزبانی میشود تا بار ترافیک برنامهنویسی جدا از سایت اصلی توزیع شود. هرگز مستقیم به بکاند پردازشی وصل نشوید — این آدرس تنها نقطهی ورود پایدار و پشتیبانیشده برای API است.
https://api.optipic.ir/api?action=<endpoint>احراز هویت
هر درخواست (بهجز دانلود، که با یک شناسهی غیرقابلحدس محافظت میشود) به یک جفت ایمیل و کلید API نیاز دارد.
کجا فرستاده میشوند؟
همیشه در بدنهی درخواست — بهصورت فیلد JSON یا multipart، نه هدر HTTP. برای درخواستهای GET پیگیری وضعیت که بدنه ندارند، بهصورت query string فرستاده میشوند.
curl -X POST "https://api.optipic.ir/api?action=v1-create" \
-H "Content-Type: application/json" \
-d '{"email":"you@example.com","token":"sk_live_51H8x...redacted","imageUrl":"https://example.com/photo.jpg"}'$payload = json_encode([
'email' => 'you@example.com',
'token' => $token,
'imageUrl' => $imageUrl,
]);
$ch = curl_init('https://api.optipic.ir/api?action=v1-create');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $payload,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_RETURNTRANSFER => true,
]);
$job = json_decode(curl_exec($ch), true);
curl_close($ch);const res = await fetch("https://api.optipic.ir/api?action=v1-create", {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, token, imageUrl }),
});import requests
r = requests.post('https://api.optipic.ir/api?action=v1-create', json={
'email': 'you@example.com',
'token': token,
'imageUrl': imageUrl,
})
job = r.json()using var client = new HttpClient();
var payload = new { email = "you@example.com", token, imageUrl };
var res = await client.PostAsJsonAsync("https://api.optipic.ir/api?action=v1-create", payload);
var job = await res.Content.ReadFromJsonAsync<JobResponse>();محدودیت آدرس IP (اختیاری)
اگر در داشبورد یک یا چند آدرس IP به لیست سفید اضافه کنید، درخواستها فقط از همان آدرسها پذیرفته میشوند. چون پلاگین از طریق همین سایت واسط صدا میزند، «آدرس تماسگیرنده» همان IP خروجی سرور میزبان سایت است، نه IP بازدیدکننده — اگر این قابلیت را فعال میکنید، IP سرور میزبان را وایتلیست کنید.
ساختار خطاها
خروجی خطای همهی endpointها یک شکل ثابت دارد — منطق برنامهتان را بر اساس errorKey بنویسید (پایدار و ثابت)، نه error (که ممکن است متنش تغییر کند).
{
"error": "Invalid API credentials.",
"errorKey": "api_token_invalid"
}محدودیتها و بودجه
401 budget_exceeded رد میشود.ساخت یک job
یک تصویر را بهینه میکند — یا با آپلود مستقیم فایل، یا با دادن آدرس یک تصویر که خودمان دانلودش میکنیم. این دو حالت با هم قابل ترکیب نیستند.
A) آپلود مستقیم فایل
بهصورت multipart/form-data.
| فیلد | الزامی؟ | توضیح |
|---|---|---|
email | بله | |
token | بله | |
file | بله | فایل تصویر |
quality | اختیاری | عدد صحیح ۱ تا ۱۰۰ |
lossless | اختیاری | true/false |
convertTo | اختیاری | "webp" یا "avif" |
maxWidth | اختیاری | عدد صحیح مثبت |
maxHeight | اختیاری | عدد صحیح مثبت |
resizeFitBoth | اختیاری | پیشفرض true؛ فقط وقتی هر دو بعد تنظیم شده باشند معنا دارد |
fixCmyk | اختیاری | تبدیل CMYK/YCCK به RGB (فقط JPEG) |
curl -X POST "https://api.optipic.ir/api?action=v1-create" \
-F "email=you@example.com" \
-F "token=sk_live_51H8x...redacted" \
-F "quality=75" \
-F "file=@/path/to/photo.jpg"$ch = curl_init('https://api.optipic.ir/api?action=v1-create');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => [
'email' => 'you@example.com',
'token' => $token,
'quality' => 75,
'file' => new CURLFile('/path/to/photo.jpg'),
],
CURLOPT_RETURNTRANSFER => true,
]);
$job = json_decode(curl_exec($ch), true);
curl_close($ch);const form = new FormData();
form.append('email', email);
form.append('token', token);
form.append('quality', '75');
form.append('file', fileInput.files[0]);
const res = await fetch('https://api.optipic.ir/api?action=v1-create', { method: 'POST', body: form });
const job = await res.json();import requests
with open('photo.jpg', 'rb') as f:
r = requests.post('https://api.optipic.ir/api?action=v1-create', data={
'email': 'you@example.com',
'token': token,
'quality': 75,
}, files={'file': f})
job = r.json()using var client = new HttpClient();
using var form = new MultipartFormDataContent();
form.Add(new StringContent("you@example.com"), "email");
form.Add(new StringContent(token), "token");
form.Add(new StringContent("75"), "quality");
form.Add(new StreamContent(File.OpenRead("photo.jpg")), "file", "photo.jpg");
var res = await client.PostAsync("https://api.optipic.ir/api?action=v1-create", form);
var job = await res.Content.ReadFromJsonAsync<JobResponse>();B) بهینهسازی از روی آدرس
بهصورت JSON، همون فیلدهای بالا بهعلاوهی imageUrl بهجای file.
curl -X POST "https://api.optipic.ir/api?action=v1-create" \
-H "Content-Type: application/json" \
-d '{
"email": "you@example.com",
"token": "sk_live_51H8x...redacted",
"imageUrl": "https:\/\/example.com\/photo.jpg",
"quality": 75,
"convertTo": "webp"
}'$payload = json_encode([
'email' => 'you@example.com',
'token' => $token,
'imageUrl' => $imageUrl,
'quality' => 75,
'convertTo' => 'webp',
]);
$ch = curl_init('https://api.optipic.ir/api?action=v1-create');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $payload,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_RETURNTRANSFER => true,
]);
$job = json_decode(curl_exec($ch), true);
curl_close($ch);const res = await fetch('https://api.optipic.ir/api?action=v1-create', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, token, imageUrl, quality: 75, convertTo: 'webp' }),
});
const job = await res.json();import requests
r = requests.post('https://api.optipic.ir/api?action=v1-create', json={
'email': 'you@example.com',
'token': token,
'imageUrl': 'https://example.com/photo.jpg',
'quality': 75,
})
job = r.json()using var client = new HttpClient();
var payload = new {
email = "you@example.com", token,
imageUrl = "https://example.com/photo.jpg",
quality = 75, convertTo = "webp",
};
var res = await client.PostAsJsonAsync("https://api.optipic.ir/api?action=v1-create", payload);
var job = await res.Content.ReadFromJsonAsync<JobResponse>();{
"id": "6a8b1916-0f6b-4577-b7ec-7bb2fcfe06a4",
"status": "Pending",
"originalFileName": "photo.jpg",
"inputSize": 70906,
"outputSize": null,
"savedPercent": null,
"convertTo": null,
"errorMessage": null,
"createdAt": "2026-08-21T07:14:36.10Z",
"completedAt": null,
"downloadUrl": null,
"alreadyOptimal": null,
"outputWidth": null,
"outputHeight": null
}مقدار id را نگه دارید — برای پیگیری وضعیت لازمش دارید.
401 api_token_invalid، 401 budget_exceeded، 400 invalid_request، 400 unsupported_file_type، 400 file_too_large، و برای حالت B: 400 invalid_url / 400 ssrf_blocked / 400 download_failed.گرفتن وضعیت job
همان شکل پاسخ ساخت job را برمیگرداند، بهروزشده. مالکیت بررسی میشود — job ساختهشده با اطلاعات یک حساب دیگر، با ۴۰۴ رد میشود (نه ۴۰۳، تا نشود با حدس زدن id فهمید یک job واقعاً وجود دارد یا نه).
curl "https://api.optipic.ir/api?action=v1-status&id=6a8b1916-0f6b-4577-b7ec-7bb2fcfe06a4&email=you@example.com&token=sk_live_51H8x...redacted"$query = http_build_query([
'id' => $jobId,
'email' => 'you@example.com',
'token' => $token,
]);
$ch = curl_init('https://api.optipic.ir/api?action=v1-status&' . $query);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$job = json_decode(curl_exec($ch), true);
curl_close($ch);const url = new URL('https://api.optipic.ir/api');
url.searchParams.set('action', 'v1-status');
url.searchParams.set('id', jobId);
url.searchParams.set('email', email);
url.searchParams.set('token', token);
const job = await (await fetch(url)).json();r = requests.get('https://api.optipic.ir/api', params={
'action': 'v1-status', 'id': job_id, 'email': email, 'token': token,
})
job = r.json()using var client = new HttpClient();
var url = "https://api.optipic.ir/api?action=v1-status" +
$"&id={jobId}&email={email}&token={token}";
var job = await client.GetFromJsonAsync<JobResponse>(url);status یکی از این چهار مقدار است: "Pending"، "Processing"، "Done"، یا "Failed". تا رسیدن به یکی از این دو حالت آخر پیگیری کنید.
{
"id": "6a8b1916-0f6b-4577-b7ec-7bb2fcfe06a4",
"status": "Done",
"originalFileName": "photo.jpg",
"inputSize": 70906,
"outputSize": 42905,
"savedPercent": 39.5,
"convertTo": "webp",
"errorMessage": null,
"createdAt": "2026-08-21T07:14:36.10Z",
"completedAt": "2026-08-21T07:14:39.14Z",
"downloadUrl": "/api?action=download&id=6a8b1916-0f6b-4577-b7ec-7bb2fcfe06a4",
"alreadyOptimal": false,
"outputWidth": 700,
"outputHeight": 525
}downloadUrl یک مسیر نسبی به همین سایت است — همیشه دامنهی خودتان را جلوی آن بگذارید، هرگز بهعنوان آدرس مستقل فرض نکنید. وقتی alreadyOptimal: true باشد، یعنی فایل ورودی از قبل به بهترین حالت ممکن رسیده بوده — دانلود همچنان کار میکند و همان فایل اصلی را برمیگرداند.دانلود نتیجه
بدون نیاز به احراز هویت — خودِ شناسهی غیرقابلحدس job کنترل دسترسی را انجام میدهد، مثل بقیهی لینکهای دانلود این سایت. فایل را با Content-Type و نام واقعی فایل استریم میکند. فقط وقتی job به "Done" رسیده باشد کار میکند.
curl -o result.jpg "https://api.optipic.ir/api?action=download&id=6a8b1916-0f6b-4577-b7ec-7bb2fcfe06a4"$ch = curl_init('https://api.optipic.ir/api?action=download&id=' . $jobId);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$bytes = curl_exec($ch);
curl_close($ch);
file_put_contents('result.jpg', $bytes);const blob = await (await fetch('https://api.optipic.ir/api?action=download&id=' + jobId)).blob();r = requests.get('https://api.optipic.ir/api', params={'action': 'download', 'id': job_id})
with open('result.jpg', 'wb') as f:
f.write(r.content)using var client = new HttpClient();
var bytes = await client.GetByteArrayAsync(
$"https://api.optipic.ir/api?action=download&id={jobId}");
await File.WriteAllBytesAsync("result.jpg", bytes);ساخت یک batch
یک job جدا بهازای هر آدرس در لیست میسازد (حداکثر ۵۰ تا) — مناسب برای «همهی کتابخانهی رسانه را یکجا بهینه کن». فقط با آدرس کار میکند؛ آپلود فایل در این حالت پشتیبانی نمیشود.
| فیلد | الزامی؟ | توضیح |
|---|---|---|
email | بله | |
token | بله | |
urls | بله | آرایهای از آدرسها، حداکثر ۵۰ تا |
quality, lossless, convertTo, maxWidth, maxHeight, resizeFitBoth, fixCmyk | اختیاری | دقیقاً مثل ساخت job تکی — روی همهی آدرسهای لیست یکسان اعمال میشود. |
curl -X POST "https://api.optipic.ir/api?action=v1-batch-create" \
-H "Content-Type: application/json" \
-d '{
"email": "you@example.com",
"token": "sk_live_51H8x...redacted",
"urls": [
"https:\/\/example.com\/a.jpg",
"https:\/\/example.com\/b.jpg"
],
"quality": 75
}'$payload = json_encode([
'email' => 'you@example.com',
'token' => $token,
'urls' => $urls,
'quality' => 75,
]);
$ch = curl_init('https://api.optipic.ir/api?action=v1-batch-create');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $payload,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_RETURNTRANSFER => true,
]);
$batch = json_decode(curl_exec($ch), true);
curl_close($ch);const res = await fetch('https://api.optipic.ir/api?action=v1-batch-create', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, token, urls, quality: 75 }),
});
const batch = await res.json();r = requests.post('https://api.optipic.ir/api?action=v1-batch-create', json={
'email': 'you@example.com', 'token': token, 'urls': urls, 'quality': 75,
})
batch = r.json()using var client = new HttpClient();
var payload = new { email = "you@example.com", token, urls, quality = 75 };
var res = await client.PostAsJsonAsync("https://api.optipic.ir/api?action=v1-batch-create", payload);
var batch = await res.Content.ReadFromJsonAsync<BatchCreateResponse>();{
"batchId": "a1ddf93e-9223-402e-b8c5-fbaa452117b1",
"items": [
{
"url": "https://example.com/a.jpg",
"jobId": "2388bd8b-208e-475a-a2ad-0aae0a71d225",
"error": null,
"errorKey": null
},
{
"url": "not-a-valid-url",
"jobId": null,
"error": "Invalid URL.",
"errorKey": "invalid_url"
}
]
}jobId: null دارد هیچوقت واقعاً job نشده (دلیلش را در errorKey همان آیتم ببینید)، بقیهی آیتمها بهطور معمول پردازش میشوند.گرفتن وضعیت یک batch
وضعیت همهی jobهای زیرمجموعهی این batch را یکجا برمیگرداند — بهجای پیگیری تکتک، فقط یک id را بررسی کنید.
curl "https://api.optipic.ir/api?action=v1-batch-status&id=a1ddf93e-9223-402e-b8c5-fbaa452117b1&email=you@example.com&token=sk_live_51H8x...redacted"$query = http_build_query([
'id' => $batchId,
'email' => 'you@example.com',
'token' => $token,
]);
$ch = curl_init('https://api.optipic.ir/api?action=v1-batch-status&' . $query);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$batch = json_decode(curl_exec($ch), true);
curl_close($ch);const url = new URL('https://api.optipic.ir/api');
url.searchParams.set('action', 'v1-batch-status');
url.searchParams.set('id', batchId);
url.searchParams.set('email', email);
url.searchParams.set('token', token);
const batch = await (await fetch(url)).json();r = requests.get('https://api.optipic.ir/api', params={
'action': 'v1-batch-status', 'id': batch_id, 'email': email, 'token': token,
})
batch = r.json()using var client = new HttpClient();
var url = "https://api.optipic.ir/api?action=v1-batch-status" +
$"&id={batchId}&email={email}&token={token}";
var batch = await client.GetFromJsonAsync<BatchStatusResponse>(url);{
"batchId": "a1ddf93e-9223-402e-b8c5-fbaa452117b1",
"createdAt": "2026-08-21T08:12:01.47Z",
"requestedCount": 3,
"jobs": [
{
"id": "2388bd8b-208e-475a-a2ad-0aae0a71d225",
"status": "Done",
"downloadUrl": "/api?action=download&id=2388bd8b-208e-475a-a2ad-0aae0a71d225",
"savedPercent": 39.5
},
{
"id": "dc0cf9e1-02ad-4110-ba71-5bcbb8eea912",
"status": "Processing",
"downloadUrl": null,
"savedPercent": null
}
]
}jobs شامل هر شیء کامل job (همان شکل v1-status) برای هر آدرسی است که واقعاً به یک job تبدیل شد — این آرایه میتواند کوتاهتر از requestedCount باشد اگر بعضی آدرسها از ابتدا رد شده باشند (به items در پاسخ ساخت batch نگاه کنید). تا وقتی همهی jobها به "Done" یا "Failed" برسند پیگیری کنید.
کدهای خطا
لیست کامل errorKeyهایی که این API برمیگردونه.
api_token_invalid
ایمیل یا توکن اشتباه/خالی است، یا مالکیت job/batch مطابقت ندارد.
budget_exceeded
بودجهی حساب تمام شده — از داشبورد بودجه را افزایش دهید.
ip_not_whitelisted
IP تماسگیرنده در لیست سفید حساب نیست.
invalid_request
فیلد لازم غایب است یا مقدار یک تنظیم نامعتبر است.
unsupported_file_type
پسوند یا نوع فایل پشتیبانی نمیشود (فقط JPG/PNG/WebP/AVIF).
file_too_large
فایل از سقف ۵۰ مگابایت بیشتر است.
invalid_url
آدرس دادهشده معتبر نیست (فقط در حالت URL).
ssrf_blocked
آدرس به یک شبکهی خصوصی/داخلی اشاره میکند و مسدود شده.
download_failed
آدرس دادهشده پاسخ نداد یا قابلدسترس نبود.
not_found
شناسهی job یا batch وجود ندارد، یا متعلق به حساب دیگری است.
unexpected_error
خطای موقت سرویس — قابل تلاش مجدد است.