مستندات API مربوط به MakeFav
بستههای کامل favicon را از کد خودتان، اسکریپتهای بیلد و پایپلاینهای CI بسازید. با یک درخواست، هر تصویری به favicon.ico، آیکونهای Apple touch، آیکونهای Android و PWA، یک web manifest و کد HTML آماده تبدیل میشود.
در این صفحه
شروع سریع
API مربوط به MakeFav یک REST API ساده مبتنی بر HTTPS و JSON است. همه اندپوینتها زیر یک آدرس پایه قرار دارند:
https://makefav.com/api/v1 - ایجاد حساب کاربری رایگان
ثبتنام کنید، آدرس ایمیل خود را تأیید کنید و اشتراک خبرنامه MakeFav را فعال نگه دارید – این تنها شرط طرح رایگان است. - ایجاد کلید API
صفحه کلیدهای API را در حساب کاربری خود باز کنید و یک کلید شخصی بسازید. این کلید با mf_ شروع میشود و فقط یک بار نمایش داده میشود، پس آن را در جای امنی ذخیره کنید. مدیریت کلیدهای API - ارسال اولین درخواست
یک تصویر را به اندپوینت generate ارسال کنید و فایل ZIP دریافتی را ذخیره کنید:
curl --fail-with-body -sS https://makefav.com/api/v1/generate \
-H "Authorization: Bearer $MAKEFAV_API_KEY" \
-F "[email protected]" \
-F "app_name=My App" \
-F "theme_color=#2f9e68" \
-F "radius=20" \
-o favicons.zip Unzip favicons.zip, upload the files to your website and paste the HTML code from the end of readme-makefav.txt into the <head> of every page.
احراز هویت
هر درخواست به یک اندپوینت محافظتشده باید شامل یک کلید API شخصی باشد. میتوانید در هر زمان در صفحه حساب کاربری خود کلیدها را ایجاد کنید، نامگذاری کنید و لغو کنید: کلیدهای API
Send the key as a bearer token in the Authorization header, or – if your HTTP client makes that awkward – in the X-API-Key header. Both are equivalent.
Authorization: Bearer mf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# or, alternatively
X-API-Key: mf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Missing or invalid keys return 401 Unauthorized. The GET /sizes and GET /openapi.json endpoints do not require a key.
محدودیت نرخ درخواست
بهطور پیشفرض هر کلید API میتواند در هر ساعت 100 درخواست ارسال کند. هر پاسخ احراز هویتشده نشان میدهد در چه وضعیتی هستید:
| هدر | توضیحات |
|---|---|
X-RateLimit-Limit | حداکثر تعداد درخواست مجاز در بازه فعلی. |
X-RateLimit-Remaining | درخواستهای باقیمانده در بازه فعلی. |
X-RateLimit-Reset | زمانسنج Unix (ثانیه، UTC) برای بازنشانی بازه. |
HTTP/1.1 200 OK
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 97
X-RateLimit-Reset: 1767225600 When the limit is exceeded the API responds with HTTP 429 and the error code rate_limited. Wait until the time in X-RateLimit-Reset before retrying – do not retry in a tight loop.
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1767225600
{"error": {"code": "rate_limited", "message": "Rate limit exceeded. Try again after the reset time."}} You can check your current quota at any time with GET /me.
اندپوینتها
| اندپوینت | احراز هویت | توضیحات |
|---|---|---|
POST /generate | کلید API | ساخت یک بسته کامل favicon. |
GET /me | کلید API | حساب کاربری شما و وضعیت فعلی محدودیت نرخ درخواست. |
GET /sizes | هیچکدام | فهرست همه فایلهای آیکون و اندازههایی که مولد تولید میکند. |
GET /openapi.json | هیچکدام | مشخصات OpenAPI 3.1 قابلخواندن برای ماشین. |
ساخت بسته فاویکون
/generateیک بسته کامل فاویکون را از یک تصویر منبع میسازد. تصویر را به یکی از سه روش زیر ارسال کنید:
| نوع محتوا | فیلد تصویر | توضیحات |
|---|---|---|
multipart/form-data | image | آپلود فایل. پیشنهادی – کارآمدترین گزینه. |
application/json | image_base64 | Base64-encoded image, either raw base64 or a data URL such as data:image/png;base64,iVBOR…. |
application/json | image_url | نشانی عمومی http یا https تصویر. سرور آن را دانلود میکند (حداکثر ۱۰ مگابایت). |
فرمتهای ورودی پشتیبانیشده: PNG، JPG، WebP، AVIF، GIF، BMP، SVG و ICO. حداکثر حجم فایل: ۱۰ مگابایت.
پارامترها
همه پارامترها اختیاری هستند. آنها را بهصورت فیلدهای فرم (multipart) یا ویژگیهای JSON ارسال کنید. مقادیر نامعتبر به مقدار پیشفرض برمیگردند.
| نام | نوع / محدوده | پیشفرض | توضیحات |
|---|---|---|---|
app_name | رشته، حداکثر ۶۰ نویسه | My Website | نام وبسایت یا اپلیکیشن شما که در manifest.json و صفحه نمونه استفاده میشود. |
short_name | رشته، حداکثر ۲۴ نویسه | ۱۲ نویسه اول app_name | نام کوتاهی که زیر آیکون در صفحه اصلی اندروید نمایش داده میشود. |
theme_color | #rrggbb | #ffffff | رنگ رابط کاربری مرورگر (متاتگ theme-color و manifest). |
tile_color | #rrggbb | مانند theme_color | رنگ پسزمینه کاشیهای Start در Windows. |
background | transparent | #rrggbb | transparent | پسزمینه آیکونهای مرورگر، Android و Windows. |
apple_background | #rrggbb | #ffffff | پسزمینه آیکونهای Apple touch و آیکون maskable (iOS از شفافیت پشتیبانی نمیکند). اگر پسزمینه یک رنگ باشد نادیده گرفته میشود و همان رنگ استفاده میشود. |
padding | عدد صحیح، ۰ تا ۴۰ (٪) | 0 | فضای خالی اطراف تصویر، بهصورت درصدی از اندازه آیکون. |
radius | عدد صحیح، ۰ تا ۵۰ (٪) | 0 | گوشههای گرد. مقدار ۵۰ دایره میسازد. روی آیکونهای Apple اعمال نمیشود، چون iOS خودش آنها را گرد میکند. |
zoom | عدد صحیح، ۵۰ تا ۴۰۰ (٪) | 100 | مقیاس تصویر داخل آیکون. مقادیر بالاتر از ۱۰۰ تصویر را برش میدهند. |
offset_x, offset_y | عدد، از ۱- تا ۱ | 0 | تصویر را بهصورت افقی / عمودی جابهجا میکند، بهصورت کسری از اندازه آیکون. |
path | رشته | / | پوشهای روی سرور شما که آیکونها در آن قرار میگیرند. در قطعه HTML، manifest و browserconfig استفاده میشود. |
display | standalone | fullscreen | minimal-ui | browser | standalone | حالت نمایش PWA که در manifest نوشته میشود. |
pixelated | auto | 1 | 0 | auto | مقیاسدهی تیز با نزدیکترین همسایه برای پیکسلآرت. حالت auto آن را برای تصاویر ۶۴ پیکسل یا کوچکتر فعال میکند. |
maskable | 1 | 0 | 1 | فایل maskable-icon-512x512.png را نیز با حاشیه ناحیه امن برای آیکونهای تطبیقی Android میسازد. |
ico_sizes | فهرست جداشده با کاما از 16، 24، 32، 48، 64، 128، 256 | 16,32,48 | اندازههای جاسازیشده در favicon.ico. |
groups | فهرست جداشده با کاما از favicon، apple، android، ms | favicon,apple,android,ms | مجموعه آیکونهایی که ساخته میشوند: فاویکونهای مرورگر، آیکونهای Apple touch، آیکونهای Android / PWA و کاشیهای Windows. |
format | zip | json | zip | فرمت پاسخ – پایین را ببینید. |
پاسخ
format=zip- Binary ZIP archive with
Content-Type: application/zipandContent-Disposition: attachment. Default. format=json- JSON object with the package
id(32 hex characters), thehtmlsnippet for your <head> and afilesarray; each file hasname,mime,size(bytes) andbase64contents.
نمونه درخواست – multipart، پاسخ ZIP
curl --fail-with-body -sS https://makefav.com/api/v1/generate \
-H "Authorization: Bearer $MAKEFAV_API_KEY" \
-F "[email protected]" \
-F "app_name=My App" \
-F "theme_color=#2f9e68" \
-F "radius=20" \
-o favicons.zip HTTP/1.1 200 OK
Content-Type: application/zip
Content-Disposition: attachment
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 99
X-RateLimit-Reset: 1767225600
<binary ZIP data> نمونه درخواست – JSON با نشانی تصویر، پاسخ JSON
curl --fail-with-body -sS https://makefav.com/api/v1/generate \
-H "Authorization: Bearer $MAKEFAV_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"image_url": "https://example.com/logo.png",
"app_name": "My App",
"theme_color": "#2f9e68",
"radius": 20,
"groups": "favicon,apple,android",
"format": "json"
}' {
"id": "9f86d081884c7d659a2feaa0c55ad015",
"html": "<link rel=\"apple-touch-icon\" sizes=\"57x57\" href=\"/apple-icon-57x57.png\">\n…\n<meta name=\"theme-color\" content=\"#2f9e68\">",
"files": [
{"name": "favicon.ico", "mime": "image/x-icon", "size": 15086, "base64": "AAABAAMAEBAAAAEAIABoBAAANgAAACAg…"},
{"name": "favicon-16x16.png", "mime": "image/png", "size": 612, "base64": "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQ…"},
{"name": "manifest.json", "mime": "application/json", "size": 1094, "base64": "ewogICAgIm5hbWUiOiAiTXkgQXBwIiwK…"}
]
}
دریافت اطلاعات حساب
/meکاربری را که کلید API متعلق به اوست و وضعیت فعلی محدودیت نرخ را برمیگرداند. برای بررسی اعتبار کلید مفید است. نیاز به احراز هویت دارد؛ بدون پارامتر.
نمونه درخواست
curl -sS https://makefav.com/api/v1/me \
-H "Authorization: Bearer $MAKEFAV_API_KEY" نمونه پاسخ
{
"id": 1,
"email": "[email protected]",
"name": "Jane Doe",
"rate_limit": {"limit": 100, "remaining": 97, "reset": 1767225600}
}
فهرست اندازههای آیکون
/sizesReturns every icon file the generator can produce, with its pixel size and group. No authentication and no parameters. The group value matches the groups parameter of POST /generate.
نمونه درخواست
curl -sS https://makefav.com/api/v1/sizes نمونه پاسخ
{
"files": [
{"name": "favicon-16x16.png", "size": 16, "group": "favicon"},
{"name": "favicon-32x32.png", "size": 32, "group": "favicon"},
{"name": "apple-touch-icon.png", "size": 180, "group": "apple"},
{"name": "android-icon-192x192.png", "size": 192, "group": "android"},
{"name": "ms-icon-144x144.png", "size": 144, "group": "ms"}
]
}
مشخصات OpenAPI
/openapi.jsonتوضیحات OpenAPI 3.1 این API را برمیگرداند. بدون نیاز به احراز هویت. آن را در Postman، Insomnia یا Swagger UI وارد کنید، یا برای ساخت کلاینت تایپدار برای زبان خود از آن استفاده کنید.
curl -sS https://makefav.com/api/v1/openapi.json -o makefav-openapi.json خطاها
Successful requests return HTTP 200. Every error returns a JSON body with a stable, machine-readable code and a human-readable message. Always branch on the code, not on the message text.
HTTP/1.1 422 Unprocessable Content
Content-Type: application/json
{
"error": {
"code": "invalid_image",
"message": "The uploaded file could not be decoded as an image."
}
} | وضعیت HTTP | کد خطا | مفهوم |
|---|---|---|
| 400 | bad_request | درخواست نادرست است؛ مثلاً هیچ تصویری ارسال نشده یا بدنه JSON نامعتبر است. |
| 401 | unauthorized | کلید API وجود ندارد یا نامعتبر است. |
| 403 | forbidden | ایمیل صاحب کلید تأیید نشده، اشتراک خبرنامه غیرفعال است یا حساب مسدود شده است. |
| 413 | file_too_large | حجم تصویر بیشتر از ۱۰ مگابایت است. |
| 415 | unsupported_type | نوع فایل یا نوع محتوای درخواست پشتیبانی نمیشود. |
| 422 | invalid_image | فایل بهعنوان تصویر قابل رمزگشایی نبود یا نشانی تصویر قابل دانلود نبود. |
| 429 | rate_limited | درخواستهای بیش از حد. تا X-RateLimit-Reset صبر کنید. |
| 500 | server_error | مشکلی در سمت ما رخ داده است. بعداً دوباره تلاش کنید؛ اگر ادامه داشت با پشتیبانی تماس بگیرید. |
فایلهای خروجی
With all groups enabled, a package contains the files below. Files from disabled groups are left out.
| فایل | اندازه | گروه |
|---|---|---|
favicon.ico | 16, 32, 48 (قابل تنظیم) | همیشه |
favicon-16x16.png | 16 × 16 | favicon |
favicon-32x32.png | 32 × 32 | favicon |
favicon-96x96.png | 96 × 96 | favicon |
apple-icon-57x57.png | 57 × 57 | apple |
apple-icon-60x60.png | 60 × 60 | apple |
apple-icon-72x72.png | 72 × 72 | apple |
apple-icon-76x76.png | 76 × 76 | apple |
apple-icon-114x114.png | 114 × 114 | apple |
apple-icon-120x120.png | 120 × 120 | apple |
apple-icon-144x144.png | 144 × 144 | apple |
apple-icon-152x152.png | 152 × 152 | apple |
apple-icon-180x180.png | 180 × 180 | apple |
apple-icon.png | 192 × 192 | apple |
apple-icon-precomposed.png | 192 × 192 | apple |
apple-touch-icon.png | 180 × 180 | apple |
android-icon-36x36.png | 36 × 36 | android |
android-icon-48x48.png | 48 × 48 | android |
android-icon-72x72.png | 72 × 72 | android |
android-icon-96x96.png | 96 × 96 | android |
android-icon-144x144.png | 144 × 144 | android |
android-icon-192x192.png | 192 × 192 | android |
android-icon-512x512.png | 512 × 512 | android |
web-app-manifest-192x192.png | 192 × 192 | android |
web-app-manifest-512x512.png | 512 × 512 | android |
maskable-icon-512x512.png | 512 × 512 | android |
ms-icon-70x70.png | 70 × 70 | ms |
ms-icon-144x144.png | 144 × 144 | ms |
ms-icon-150x150.png | 150 × 150 | ms |
ms-icon-310x310.png | 310 × 310 | ms |
فایلهای اضافی
| فایل | شامل | توضیحات |
|---|---|---|
favicon.svg | فقط برای ورودی SVG بدون برش، زوم، حاشیه، گوشه گرد یا پسزمینه | نسخه پاکسازیشده SVG شما برای مرورگرهایی که از فاویکون برداری پشتیبانی میکنند. |
manifest.json, site.webmanifest | android | manifest وباپ برای Android و PWAهای قابل نصب (دو نسخه یکسان). |
browserconfig.xml | ms | پیکربندی کاشی Windows با رنگ کاشی شما. |
readme-makefav.txt | همیشه | راهنمای نصب که در پایان آن کد HTML مخصوص <head> شما قرار دارد. |
نمونه کد
Each example uploads logo.png with a few options and saves favicons.zip, handling API errors. Set the environment variable MAKEFAV_API_KEY to your API key first.
آپلود multipart:
# Multipart upload (recommended). --fail-with-body exits non-zero on HTTP errors
# and still saves the JSON error body, so you can inspect it.
curl --fail-with-body -sS https://makefav.com/api/v1/generate \
-H "Authorization: Bearer $MAKEFAV_API_KEY" \
-F "[email protected]" \
-F "app_name=My App" \
-F "theme_color=#2f9e68" \
-F "radius=20" \
-o favicons.zip \
|| { echo "Request failed:"; cat favicons.zip; rm -f favicons.zip; exit 1; } بدنه JSON با تصویر کدگذاریشده base64 (نیازمند jq):
# JSON body with a base64-encoded image (built with jq to avoid argument length limits)
base64 < logo.png | tr -d '\n' > logo.b64
jq -n --rawfile img logo.b64 \
'{image_base64: $img, app_name: "My App", theme_color: "#2f9e68", radius: 20}' \
| curl --fail-with-body -sS https://makefav.com/api/v1/generate \
-H "Authorization: Bearer $MAKEFAV_API_KEY" \
-H "Content-Type: application/json" \
--data-binary @- \
-o favicons.zip \
|| { echo "Request failed:"; cat favicons.zip; rm -f favicons.zip; exit 1; } <?php
// Requires the curl extension. Run: MAKEFAV_API_KEY=mf_... php favicons.php
$apiKey = getenv('MAKEFAV_API_KEY') ?: exit("Set MAKEFAV_API_KEY first\n");
$ch = curl_init('https://makefav.com/api/v1/generate');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 60,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
CURLOPT_POSTFIELDS => [
'image' => new CURLFile('logo.png', 'image/png', 'logo.png'),
'app_name' => 'My App',
'theme_color' => '#2f9e68',
'radius' => '20',
],
]);
$body = curl_exec($ch);
if ($body === false) {
fwrite(STDERR, 'Request failed: ' . curl_error($ch) . PHP_EOL);
exit(1);
}
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
if ($status !== 200) {
$error = json_decode($body, true)['error'] ?? ['code' => 'http_' . $status, 'message' => substr($body, 0, 200)];
fwrite(STDERR, "Error {$status} {$error['code']}: {$error['message']}" . PHP_EOL);
exit(1);
}
file_put_contents('favicons.zip', $body);
echo 'Saved favicons.zip (' . strlen($body) . " bytes)\n"; # pip install requests · Run: MAKEFAV_API_KEY=mf_... python favicons.py
import os
import sys
import requests
API_KEY = os.environ["MAKEFAV_API_KEY"]
try:
with open("logo.png", "rb") as logo:
resp = requests.post(
"https://makefav.com/api/v1/generate",
headers={"Authorization": f"Bearer {API_KEY}"},
files={"image": ("logo.png", logo, "image/png")},
data={"app_name": "My App", "theme_color": "#2f9e68", "radius": 20},
timeout=60,
)
except requests.RequestException as exc:
sys.exit(f"Request failed: {exc}")
if resp.status_code != 200:
try:
err = resp.json()["error"]
sys.exit(f"Error {resp.status_code} {err['code']}: {err['message']}")
except (ValueError, KeyError, TypeError):
sys.exit(f"Error {resp.status_code}: {resp.text[:200]}")
with open("favicons.zip", "wb") as out:
out.write(resp.content)
remaining = resp.headers.get("X-RateLimit-Remaining")
print(f"Saved favicons.zip ({len(resp.content)} bytes), {remaining} requests left this hour") // favicons.mjs — Node.js 18+, no dependencies. Run: MAKEFAV_API_KEY=mf_... node favicons.mjs
import { readFile, writeFile } from 'node:fs/promises';
const form = new FormData();
form.append('image', new Blob([await readFile('logo.png')], { type: 'image/png' }), 'logo.png');
form.append('app_name', 'My App');
form.append('theme_color', '#2f9e68');
form.append('radius', '20');
const res = await fetch('https://makefav.com/api/v1/generate', {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.MAKEFAV_API_KEY}` },
body: form,
});
if (!res.ok) {
const body = await res.json().catch(() => null);
console.error(`Error ${res.status} ${body?.error?.code ?? ''}: ${body?.error?.message ?? res.statusText}`);
process.exit(1);
}
await writeFile('favicons.zip', Buffer.from(await res.arrayBuffer()));
console.log(`Saved favicons.zip, ${res.headers.get('x-ratelimit-remaining')} requests left this hour`); <input type="file" id="logo" accept="image/*">
<button type="button" id="go">Generate favicons</button>
<script>
// Never put your API key in browser code. Point ENDPOINT at your own backend route,
// which forwards the multipart body to https://makefav.com/api/v1/generate and adds
// the "Authorization: Bearer mf_..." header on the server.
const ENDPOINT = '/my-backend/favicons';
document.getElementById('go').addEventListener('click', async () => {
const file = document.getElementById('logo').files[0];
if (!file) {
alert('Please choose an image first.');
return;
}
const form = new FormData();
form.append('image', file);
form.append('app_name', 'My App');
form.append('theme_color', '#2f9e68');
form.append('radius', '20');
try {
const res = await fetch(ENDPOINT, { method: 'POST', body: form });
if (!res.ok) {
const body = await res.json().catch(() => null);
throw new Error(body?.error?.message || `HTTP ${res.status}`);
}
const url = URL.createObjectURL(await res.blob());
const a = Object.assign(document.createElement('a'), { href: url, download: 'favicons.zip' });
document.body.append(a);
a.click();
a.remove();
setTimeout(() => URL.revokeObjectURL(url), 1000);
} catch (err) {
alert('Favicon generation failed: ' + err.message);
}
});
</script> // go run favicons.go (MAKEFAV_API_KEY must be set)
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"mime/multipart"
"net/http"
"net/textproto"
"os"
"time"
)
func main() {
if err := run(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
func run() error {
var body bytes.Buffer
w := multipart.NewWriter(&body)
logo, err := os.ReadFile("logo.png")
if err != nil {
return err
}
h := make(textproto.MIMEHeader)
h.Set("Content-Disposition", `form-data; name="image"; filename="logo.png"`)
h.Set("Content-Type", "image/png")
part, err := w.CreatePart(h)
if err != nil {
return err
}
if _, err := part.Write(logo); err != nil {
return err
}
for k, v := range map[string]string{"app_name": "My App", "theme_color": "#2f9e68", "radius": "20"} {
if err := w.WriteField(k, v); err != nil {
return err
}
}
if err := w.Close(); err != nil {
return err
}
req, err := http.NewRequest(http.MethodPost, "https://makefav.com/api/v1/generate", &body)
if err != nil {
return err
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("MAKEFAV_API_KEY"))
req.Header.Set("Content-Type", w.FormDataContentType())
client := &http.Client{Timeout: 60 * time.Second}
resp, err := client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
var apiErr struct {
Error struct {
Code string `json:"code"`
Message string `json:"message"`
} `json:"error"`
}
_ = json.NewDecoder(resp.Body).Decode(&apiErr)
return fmt.Errorf("error %d %s: %s", resp.StatusCode, apiErr.Error.Code, apiErr.Error.Message)
}
zip, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
if err := os.WriteFile("favicons.zip", zip, 0o644); err != nil {
return err
}
fmt.Printf("Saved favicons.zip (%d bytes)\n", len(zip))
return nil
} # ruby favicons.rb (MAKEFAV_API_KEY must be set) — standard library only
require "net/http"
require "json"
require "uri"
uri = URI("https://makefav.com/api/v1/generate")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{ENV.fetch("MAKEFAV_API_KEY")}"
res = File.open("logo.png", "rb") do |logo|
req.set_form(
[
["image", logo, { filename: "logo.png", content_type: "image/png" }],
["app_name", "My App"],
["theme_color", "#2f9e68"],
["radius", "20"]
],
"multipart/form-data"
)
Net::HTTP.start(uri.host, uri.port, use_ssl: true, read_timeout: 60) { |http| http.request(req) }
end
unless res.is_a?(Net::HTTPSuccess)
err = (JSON.parse(res.body)["error"] rescue nil) || { "code" => res.code, "message" => res.body.to_s[0, 200] }
abort "Error #{res.code} #{err["code"]}: #{err["message"]}"
end
File.binwrite("favicons.zip", res.body)
puts "Saved favicons.zip (#{res.body.bytesize} bytes)" // .NET 6+ console app (Program.cs, top-level statements, implicit usings enabled)
using System.Net.Http.Headers;
using System.Text.Json;
using var http = new HttpClient { Timeout = TimeSpan.FromSeconds(60) };
http.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("MAKEFAV_API_KEY"));
using var form = new MultipartFormDataContent();
var image = new ByteArrayContent(await File.ReadAllBytesAsync("logo.png"));
image.Headers.ContentType = new MediaTypeHeaderValue("image/png");
form.Add(image, "image", "logo.png");
form.Add(new StringContent("My App"), "app_name");
form.Add(new StringContent("#2f9e68"), "theme_color");
form.Add(new StringContent("20"), "radius");
using var response = await http.PostAsync("https://makefav.com/api/v1/generate", form);
if (!response.IsSuccessStatusCode)
{
var body = await response.Content.ReadAsStringAsync();
string code = "", message = body;
try
{
var error = JsonDocument.Parse(body).RootElement.GetProperty("error");
code = error.GetProperty("code").GetString() ?? "";
message = error.GetProperty("message").GetString() ?? "";
}
catch (Exception e) when (e is JsonException or KeyNotFoundException or InvalidOperationException) { }
Console.Error.WriteLine($"Error {(int)response.StatusCode} {code}: {message}");
return 1;
}
await File.WriteAllBytesAsync("favicons.zip", await response.Content.ReadAsByteArrayAsync());
Console.WriteLine("Saved favicons.zip");
return 0; // Java 11+, no dependencies. Run: MAKEFAV_API_KEY=mf_... java MakeFav.java
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.UUID;
public class MakeFav {
public static void main(String[] args) throws IOException, InterruptedException {
String boundary = "----MakeFav" + UUID.randomUUID().toString().replace("-", "");
Map<String, String> fields = new LinkedHashMap<>();
fields.put("app_name", "My App");
fields.put("theme_color", "#2f9e68");
fields.put("radius", "20");
// Build the multipart/form-data body by hand
ByteArrayOutputStream body = new ByteArrayOutputStream();
for (Map.Entry<String, String> field : fields.entrySet()) {
body.write(("--" + boundary + "\r\n"
+ "Content-Disposition: form-data; name=\"" + field.getKey() + "\"\r\n\r\n"
+ field.getValue() + "\r\n").getBytes(StandardCharsets.UTF_8));
}
body.write(("--" + boundary + "\r\n"
+ "Content-Disposition: form-data; name=\"image\"; filename=\"logo.png\"\r\n"
+ "Content-Type: image/png\r\n\r\n").getBytes(StandardCharsets.UTF_8));
body.write(Files.readAllBytes(Path.of("logo.png")));
body.write(("\r\n--" + boundary + "--\r\n").getBytes(StandardCharsets.UTF_8));
HttpRequest request = HttpRequest.newBuilder(URI.create("https://makefav.com/api/v1/generate"))
.timeout(Duration.ofSeconds(60))
.header("Authorization", "Bearer " + System.getenv("MAKEFAV_API_KEY"))
.header("Content-Type", "multipart/form-data; boundary=" + boundary)
.POST(HttpRequest.BodyPublishers.ofByteArray(body.toByteArray()))
.build();
HttpResponse<byte[]> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofByteArray());
if (response.statusCode() != 200) {
// Error body is JSON: {"error":{"code":"...","message":"..."}}
System.err.println("Error " + response.statusCode() + ": "
+ new String(response.body(), StandardCharsets.UTF_8));
System.exit(1);
}
Files.write(Path.of("favicons.zip"), response.body());
System.out.println("Saved favicons.zip (" + response.body().length + " bytes)");
}
} گردشکار GitHub Actions – فرمت JSON، فایلها با jq رمزگشایی میشوند:
# .github/workflows/favicons.yml — regenerate favicons whenever the logo changes.
# Add your key as a repository secret named MAKEFAV_API_KEY.
name: Favicons
on:
push:
paths: ['branding/logo.png']
workflow_dispatch:
jobs:
favicons:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Generate favicon package (JSON format)
env:
MAKEFAV_API_KEY: ${{ secrets.MAKEFAV_API_KEY }}
run: |
set -euo pipefail
curl --fail-with-body -sS https://makefav.com/api/v1/generate \
-H "Authorization: Bearer $MAKEFAV_API_KEY" \
-F "image=@branding/logo.png" \
-F "app_name=My App" \
-F "theme_color=#2f9e68" \
-F "radius=20" \
-F "path=/icons/" \
-F "format=json" \
-o favicons.json || { cat favicons.json; exit 1; }
mkdir -p public/icons
# Decode every file from the JSON response (jq is preinstalled on GitHub runners)
jq -r '.files[] | "\(.name) \(.base64)"' favicons.json |
while read -r name data; do
printf '%s' "$data" | base64 -d > "public/icons/$(basename "$name")"
done
jq -r '.html' favicons.json > public/icons/head-snippet.html
ls -l public/icons
- uses: actions/upload-artifact@v4
with:
name: favicons
path: public/icons اسکریپت شل ساده برای هر CI – فرمت ZIP:
#!/usr/bin/env bash
# scripts/favicons.sh — simpler variant for any CI or build step: fetch the ZIP and unpack it.
set -euo pipefail
: "${MAKEFAV_API_KEY:?Set MAKEFAV_API_KEY}"
curl --fail-with-body -sS https://makefav.com/api/v1/generate \
-H "Authorization: Bearer $MAKEFAV_API_KEY" \
-F "[email protected]" \
-F "app_name=My App" \
-F "theme_color=#2f9e68" \
-F "radius=20" \
-o favicons.zip || { cat favicons.zip; rm -f favicons.zip; exit 1; }
unzip -o -q favicons.zip -d public/
rm favicons.zip
echo "Favicons written to public/" استفاده در HTML
Upload all files to the folder you set with path, then paste the snippet into the <head> of every page. It is included at the end of readme-makefav.txt in the package and, with format=json, returned in the html field. Example for the options used in the code examples above:
<head>
<meta charset="utf-8">
<title>My App</title>
<link rel="apple-touch-icon" sizes="57x57" href="/apple-icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/apple-icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/apple-icon-72x72.png">
<link rel="apple-touch-icon" sizes="76x76" href="/apple-icon-76x76.png">
<link rel="apple-touch-icon" sizes="114x114" href="/apple-icon-114x114.png">
<link rel="apple-touch-icon" sizes="120x120" href="/apple-icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/apple-icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/apple-icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/apple-icon-180x180.png">
<link rel="icon" type="image/png" sizes="192x192" href="/android-icon-192x192.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="96x96" href="/favicon-96x96.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="icon" href="/favicon.ico" sizes="any">
<link rel="manifest" href="/manifest.json">
<meta name="msapplication-TileColor" content="#2f9e68">
<meta name="msapplication-TileImage" content="/ms-icon-144x144.png">
<meta name="msapplication-config" content="/browserconfig.xml">
<meta name="theme-color" content="#2f9e68">
</head> پس از استقرار، کش مرورگر را پاک کنید یا سایت را در یک پنجره خصوصی باز کنید – مرورگرها فاویکونها را بهشدت کش میکنند.
تاریخچه تغییرات
v1
- انتشار عمومی اولیه REST API مربوط به MakeFav.
- Endpoints
POST /generate,GET /me,GET /sizesandGET /openapi.json. - فرمتهای پاسخ ZIP و JSON، ورودی تصویر بهصورت multipart، base64 و URL.
- کلیدهای API شخصی با ۱۰۰ درخواست در ساعت.
نسخه ۱ پایدار است: ما فقط پارامترها و فیلدهای اختیاری اضافه میکنیم. تغییرات ناسازگار با اطلاع قبلی در قالب نسخه جدید منتشر میشوند.
پشتیبانی
سؤال یا گزارش اشکال دارید یا به محدودیت نرخ بالاتری نیاز دارید؟ خوشحال میشویم کمک کنیم. لطفاً زمان درخواست و کد خطا را در پیام خود بنویسید – هرگز کلید API خود را ننویسید.