תיעוד ה-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 קריא למכונה. |
יצירת חבילת favicon
/generateיוצר חבילת favicon שלמה מתמונת מקור אחת. ניתן לשלוח את התמונה באחת משלוש דרכים:
| סוג תוכן | שדה התמונה | תיאור |
|---|---|---|
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 ציבורית של התמונה. השרת מוריד אותה (עד 10MB). |
פורמטי קלט נתמכים: PNG, JPG, WebP, AVIF, GIF, BMP, SVG ו-ICO. גודל קובץ מרבי: 10MB.
פרמטרים
כל הפרמטרים אופציונליים. שלחו אותם כשדות טופס (multipart) או כמאפייני JSON. ערכים לא תקינים יוחלפו בברירת המחדל.
| שם | סוג / טווח | ברירת מחדל | תיאור |
|---|---|---|---|
app_name | מחרוזת, עד 60 תווים | My Website | שם האתר או האפליקציה שלכם, משמש ב-manifest.json ובדף הדוגמה. |
short_name | מחרוזת, עד 24 תווים | 12 התווים הראשונים של app_name | שם קצר שמוצג מתחת לאייקון במסכי הבית של Android. |
theme_color | #rrggbb | #ffffff | צבע ממשק הדפדפן (תגית meta מסוג theme-color וה-manifest). |
tile_color | #rrggbb | זהה ל-theme_color | צבע הרקע של אריחי Start ב-Windows. |
background | transparent | #rrggbb | transparent | רקע של אייקוני הדפדפן, Android ו-Windows. |
apple_background | #rrggbb | #ffffff | רקע של אייקוני Apple touch והאייקון ה-maskable (iOS אינו תומך בשקיפות). מתעלמים מהערך כאשר background הוא צבע – במקרה כזה נעשה שימוש בצבע הזה. |
padding | מספר שלם, 0–40 (%) | 0 | שטח ריק סביב התמונה, באחוזים מגודל האייקון. |
radius | מספר שלם, 0–50 (%) | 0 | פינות מעוגלות. 50 יוצר עיגול. לא חל על אייקוני Apple, ש-iOS מעגל בעצמו. |
zoom | מספר שלם, 50–400 (%) | 100 | קנה המידה של התמונה בתוך האייקון. ערכים מעל 100 חותכים את התמונה. |
offset_x, offset_y | מספר, מ-1- עד 1 | 0 | מזיז את התמונה אופקית / אנכית, כחלק מגודל האייקון. |
path | מחרוזת | / | התיקייה בשרת שלכם שבה יישמרו האייקונים. משמשת בקטע ה-HTML, ב-manifest וב-browserconfig. |
display | standalone | fullscreen | minimal-ui | browser | standalone | מצב התצוגה של PWA שנכתב ל-manifest. |
pixelated | auto | 1 | 0 | auto | שינוי גודל חד בשיטת השכן הקרוב ביותר עבור פיקסל ארט. הערך auto מפעיל אותו עבור מקורות של 64 פיקסלים ומטה. |
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 | ערכות האייקונים ליצירה: favicons לדפדפנים, אייקוני 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 עם כתובת URL של תמונה, תגובת 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 | התמונה גדולה מ-10MB. |
| 415 | unsupported_type | סוג הקובץ או סוג התוכן של הבקשה אינם נתמכים. |
| 422 | invalid_image | לא ניתן היה לפענח את הקובץ כתמונה, או שלא ניתן היה להוריד את כתובת ה-URL של התמונה. |
| 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 שלכם לדפדפנים שתומכים ב-favicon וקטורי. |
manifest.json, site.webmanifest | android | Web app 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 סקריפט shell פשוט לכל מערכת 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> לאחר הפריסה, נקו את המטמון של הדפדפן או פתחו את האתר בחלון פרטי – דפדפנים שומרים favicons במטמון בעקשנות.
יומן שינויים
v1
- הגרסה הציבורית הראשונה של MakeFav REST API.
- Endpoints
POST /generate,GET /me,GET /sizesandGET /openapi.json. - פורמטי תגובה ZIP ו-JSON, וקלט תמונה בשיטות multipart, base64 וכתובת URL.
- מפתחות API אישיים עם 100 בקשות לשעה.
גרסה 1 יציבה: אנו מוסיפים רק פרמטרים ושדות אופציונליים. שינויים שוברי תאימות ישוחררו כגרסה חדשה בהודעה מראש.
תמיכה
שאלות, דיווחי באגים או צורך במגבלת קצב גבוהה יותר? נשמח לעזור. אנא צרפו להודעה את זמן הבקשה ואת קוד השגיאה – לעולם לא את מפתח ה-API שלכם.