Τεκμηρίωση του API του MakeFav
Δημιουργήστε πλήρη πακέτα favicon από τον δικό σας κώδικα, τα build scripts και τα CI pipelines. Ένα αίτημα μετατρέπει οποιαδήποτε εικόνα σε favicon.ico, Apple touch icons, εικονίδια Android και PWA, web manifest και έτοιμο προς επικόλληση HTML.
Σε αυτή τη σελίδα
Γρήγορη εκκίνηση
Το API του MakeFav είναι ένα απλό REST API μέσω HTTPS + JSON. Όλα τα endpoints βρίσκονται κάτω από μία βασική διεύθυνση URL:
https://makefav.com/api/v1 - Δημιουργήστε δωρεάν λογαριασμό
Εγγραφείτε, επιβεβαιώστε τη διεύθυνση email σας και διατηρήστε ενεργή τη συνδρομή στο newsletter του MakeFav – αυτή είναι η μόνη προϋπόθεση του δωρεάν πλάνου. - Δημιουργήστε ένα API key
Ανοίξτε τη σελίδα κλειδιών API στον λογαριασμό σας και δημιουργήστε ένα προσωπικό κλειδί. Ξεκινά με mf_ και εμφανίζεται μόνο μία φορά, γι' αυτό αποθηκεύστε το με ασφάλεια. Διαχείριση κλειδιών API - Στείλτε το πρώτο σας αίτημα
Ανεβάστε μια εικόνα στο endpoint 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.
Έλεγχος ταυτότητας
Κάθε αίτημα προς ένα προστατευμένο endpoint πρέπει να περιλαμβάνει ένα προσωπικό API key. Μπορείτε να δημιουργείτε, να ονομάζετε και να ανακαλείτε κλειδιά ανά πάσα στιγμή στη σελίδα του λογαριασμού σας: Κλειδιά 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 key μπορεί να κάνει 100 αιτήματα ανά ώρα. Κάθε αυθεντικοποιημένη απάντηση σας ενημερώνει για την τρέχουσα κατάστασή σας:
| Κεφαλίδα | Περιγραφή |
|---|---|
X-RateLimit-Limit | Μέγιστος αριθμός αιτημάτων που επιτρέπονται στο τρέχον χρονικό παράθυρο. |
X-RateLimit-Remaining | Αιτήματα που απομένουν στο τρέχον χρονικό παράθυρο. |
X-RateLimit-Reset | Unix timestamp (δευτερόλεπτα, 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.
Endpoints
| Endpoint | Έλεγχος ταυτότητας | Περιγραφή |
|---|---|---|
POST /generate | API key | Δημιουργία πλήρους πακέτου favicon. |
GET /me | API key | Ο λογαριασμός σας και η τρέχουσα κατάσταση ορίου αιτημάτων. |
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 | Δημόσιο URL http ή https της εικόνας. Ο διακομιστής την κατεβάζει (έως 10 MB). |
Υποστηριζόμενες μορφές εισόδου: PNG, JPG, WebP, AVIF, GIF, BMP, SVG και ICO. Μέγιστο μέγεθος αρχείου: 10 MB.
Παράμετροι
Όλες οι παράμετροι είναι προαιρετικές. Στείλτε τις ως πεδία φόρμας (multipart) ή ως ιδιότητες JSON. Οι μη έγκυρες τιμές αντικαθίστανται από την προεπιλογή.
| Όνομα | Τύπος / εύρος | Προεπιλογή | Περιγραφή |
|---|---|---|---|
app_name | string, έως 60 χαρακτήρες | My Website | Όνομα του ιστότοπου ή της εφαρμογής σας, που χρησιμοποιείται στο manifest.json και στην ενδεικτική σελίδα. |
short_name | string, έως 24 χαρακτήρες | οι πρώτοι 12 χαρακτήρες του app_name | Σύντομο όνομα που εμφανίζεται κάτω από το εικονίδιο στις αρχικές οθόνες του Android. |
theme_color | #rrggbb | #ffffff | Χρώμα διεπαφής του προγράμματος περιήγησης (meta tag theme-color και manifest). |
tile_color | #rrggbb | ίδιο με το theme_color | Χρώμα φόντου των πλακιδίων έναρξης των Windows. |
background | transparent | #rrggbb | transparent | Φόντο των εικονιδίων για προγράμματα περιήγησης, Android και Windows. |
apple_background | #rrggbb | #ffffff | Φόντο των εικονιδίων Apple touch και του maskable εικονιδίου (το iOS δεν υποστηρίζει διαφάνεια). Αγνοείται όταν το φόντο είναι χρώμα – τότε χρησιμοποιείται αυτό το χρώμα. |
padding | ακέραιος, 0–40 (%) | 0 | Κενός χώρος γύρω από την εικόνα, ως ποσοστό του μεγέθους του εικονιδίου. |
radius | ακέραιος, 0–50 (%) | 0 | Στρογγυλεμένες γωνίες. Το 50 δημιουργεί κύκλο. Δεν εφαρμόζεται στα εικονίδια Apple, τα οποία στρογγυλεύει το ίδιο το iOS. |
zoom | ακέραιος, 50–400 (%) | 100 | Κλίμακα της εικόνας μέσα στο εικονίδιο. Τιμές άνω του 100 περικόπτουν την εικόνα. |
offset_x, offset_y | αριθμός, -1 έως 1 | 0 | Μετακινεί την εικόνα οριζόντια / κάθετα, ως κλάσμα του μεγέθους του εικονιδίου. |
path | string | / | Φάκελος στον διακομιστή σας όπου θα βρίσκονται τα εικονίδια. Χρησιμοποιείται στο απόσπασμα HTML, στο manifest και στο browserconfig. |
display | standalone | fullscreen | minimal-ui | browser | standalone | Λειτουργία εμφάνισης PWA που γράφεται στο manifest. |
pixelated | auto | 1 | 0 | auto | Αιχμηρή κλιμάκωση πλησιέστερου γείτονα για pixel art. Η τιμή auto την ενεργοποιεί για πηγές 64 px ή μικρότερες. |
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 | Σύνολα εικονιδίων προς δημιουργία: favicon προγραμμάτων περιήγησης, εικονίδια 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, ή χρησιμοποιήστε την για να δημιουργήσετε τυποποιημένο client για τη γλώσσα σας.
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 | Το email του κατόχου του κλειδιού δεν έχει επιβεβαιωθεί, η συνδρομή στο ενημερωτικό δελτίο είναι απενεργοποιημένη ή ο λογαριασμός έχει αποκλειστεί. |
| 413 | file_too_large | Η εικόνα είναι μεγαλύτερη από 10 MB. |
| 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 script για οποιοδήποτε 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> Μετά την ανάπτυξη, καθαρίστε την προσωρινή μνήμη του προγράμματος περιήγησης ή ανοίξτε τον ιστότοπο σε ιδιωτικό παράθυρο – τα προγράμματα περιήγησης αποθηκεύουν επιθετικά τα favicon στην προσωρινή μνήμη.
Ιστορικό αλλαγών
v1
- Αρχική δημόσια έκδοση του MakeFav REST API.
- Endpoints
POST /generate,GET /me,GET /sizesandGET /openapi.json. - Μορφές απάντησης ZIP και JSON, είσοδος εικόνας μέσω multipart, base64 και URL.
- Προσωπικά κλειδιά API με 100 αιτήματα ανά ώρα.
Η έκδοση 1 είναι σταθερή: προσθέτουμε μόνο προαιρετικές παραμέτρους και πεδία. Οι αλλαγές που σπάνε τη συμβατότητα θα κυκλοφορήσουν ως νέα έκδοση με προειδοποίηση εκ των προτέρων.
Υποστήριξη
Ερωτήσεις, αναφορές σφαλμάτων ή χρειάζεστε υψηλότερο όριο αιτημάτων; Θα χαρούμε να βοηθήσουμε. Συμπεριλάβετε στο μήνυμά σας την ώρα του αιτήματος και τον κωδικό σφάλματος – ποτέ το κλειδί API σας.