מכירת גישת API (דרך מפתח/מנוי) באתר
הבעיה: מתן נתונים מבלי לאבד שליטה
פיתחתם API בעל ערך — תחזיות מזג אוויר, קטלוגי מוצרים או מודל ניקוד. שלושת הלקוחות הראשונים התחברו "באמונה טובה", אבל עם כל בקשה חדשה השרת מאט, וההכנסות נשארות אפס. ללא מערכת למכירת גישה — תוכניות, מפתחות ומגבלות — המוצר שלכם לא יכול להתרחב. יישמנו עשרות פרויקטים כאלה: מסטארטאפים עם 5,000 בקשות ביום ועד פלטפורמות פינטק המטפלות ב-50,000 RPM. זמן התגובה האופייני של ה-API שלנו הוא 20–50 אלפיות שנייה, ולוח הסטטיסטיקות מתעדכן תוך 200 אלפיות שנייה. אנו מבטיחים זמינות של 99.9% לשער ה-API. קבלו ייעוץ לפרויקט שלכם — נעריך את היקף העבודה תוך יום אחד.
הפתרון המפתח שלנו למכירת גישת API כולל יצירה אוטומטית של מפתחות API, תוכניות מנוי גמישות ל-API ומגבלות קצב. התוכניות מתחילות ב-$99 לחודש, וההתקנה הבסיסית עולה $4,500. לקוחות בדרך כלל מחזירים את ההשקעה תוך 3 חודשים.
אנחנו לא רק מוסרים מפתח — אנו מתכננים ארכיטקטורה שמתמודדת עם העומס ומונעת דליפות נתונים. להלן הסכימה המוכחת שלנו בשימוש בייצור.
ארכיטקטורה טכנית: מסד נתונים, מפתחות ואימות
סכימת מסד נתונים לתוכניות ומפתחות
הצגת טבלאות SQL
CREATE TABLE api_plans ( id SERIAL PRIMARY KEY, name TEXT, requests_per_month INTEGER, -- -1 = unlimited requests_per_minute INTEGER, endpoints JSONB, -- ['GET /v1/products', 'GET /v1/orders'] price_monthly NUMERIC(10,2), ); CREATE TABLE api_keys ( id BIGSERIAL PRIMARY KEY, user_id BIGINT REFERENCES users(id), plan_id INTEGER REFERENCES api_plans(id), key_hash TEXT UNIQUE, -- bcrypt hash ключа key_prefix CHAR(8), -- первые 8 символов для отображения status TEXT, -- active, revoked, expired expires_at TIMESTAMPTZ, created_at TIMESTAMPTZ DEFAULT NOW() ); CREATE TABLE api_usage ( id BIGSERIAL PRIMARY KEY, api_key_id BIGINT, endpoint TEXT, method TEXT, status_code SMALLINT, response_ms INTEGER, created_at TIMESTAMPTZ DEFAULT NOW() ); CREATE TABLE api_plans ( id SERIAL PRIMARY KEY, name TEXT, requests_per_month INTEGER, -- -1 = unlimited requests_per_minute INTEGER, endpoints JSONB, -- ['GET /v1/products', 'GET /v1/orders'] price_monthly NUMERIC(10,2), ); CREATE TABLE api_keys ( id BIGSERIAL PRIMARY KEY, user_id BIGINT REFERENCES users(id), plan_id INTEGER REFERENCES api_plans(id), key_hash TEXT UNIQUE, -- bcrypt hash ключа key_prefix CHAR(8), -- первые 8 символов для отображения status TEXT, -- active, revoked, expired expires_at TIMESTAMPTZ, created_at TIMESTAMPTZ DEFAULT NOW() ); CREATE TABLE api_usage ( id BIGSERIAL PRIMARY KEY, api_key_id BIGINT, endpoint TEXT, method TEXT, status_code SMALLINT, response_ms INTEGER, created_at TIMESTAMPTZ DEFAULT NOW() ); מגדיר תוכניות: מספר בקשות, נקודות קצה זמינות ומחיר. api_plans מאחסן את גיבוב המפתח — המקור מוצג פעם אחת במהלך היצירה. api_keys אוסף את כל הבקשות לניתוח. אינדקסים על api_usage ו-key_prefix מאיצים חיפושים לאלפיות שנייה.
יצירת מפתחות ואחסון עם bcrypt
הצגת קוד יצירת מפתחות
class ApiKeyService { public function generate(int $userId, int $planId): array { $rawKey = 'sk_' . Str::random(48); // Пример: sk_A1B2C3D4... ApiKey::create([ 'user_id' => $userId, 'plan_id' => $planId, 'key_hash' => Hash::make($rawKey), 'key_prefix' => substr($rawKey, 0, 8), 'status' => 'active', ]); // Ключ показывается пользователю ОДИН РАЗ — после этого только хеш return ['key' => $rawKey, 'prefix' => substr($rawKey, 0, 8)]; } } גיבוב עם bcrypt מספק המלצת OWASP לאחסון סודות. הקידומת (8 תווים) ממוקדת — חיפוש מפתח במהלך אימות לוקח פחות מ-1 אלפית שנייה. זה מונע שחזור מפתח גם אם מסד הנתונים דולף.
Middleware אימות עם חיפוש קידומת
הצגת קוד middleware
class ApiKeyAuthMiddleware { public function handle(Request $request, Closure $next): Response { $rawKey = $request->header('X-API-Key') ?? $request->bearerToken() ?? $request->query('api_key'); if (!$rawKey) { return response()->json(['error' => 'API key required'], 401); } // Быстрый поиск по префиксу, затем проверка хеша $prefix = substr($rawKey, 0, 8); $apiKey = ApiKey::where('key_prefix', $prefix)->where('status', 'active')->first(); if (!$apiKey || !Hash::check($rawKey, $apiKey->key_hash)) { return response()->json(['error' => 'Invalid API key'], 401); } $request->setApiKey($apiKey); return $next($request); } } ראשית, אנו פוסלים מפתחות עם קידומת שגויה — זה מבטל 99% מהניסיונות הפסולים ללא גישה למסד הנתונים. אימות גיבוב מלא מתרחש רק אם הקידומת תואמת. אם המפתח פג או בוטל, ה-middleware מחזיר 403 עם הסבר.
הגבלת קצב וניתוח עם Redis
יתרונות הגבלת קצב ב-Redis
הצגת קוד מגביל הקצב
class ApiRateLimiter { public function check(ApiKey $apiKey): RateLimitResult { $plan = $apiKey->plan; // Per-minute limit через Redis sliding window $minuteKey = "rate:{$apiKey->id}:minute:" . floor(time() / 60); $minuteCount = Redis::incr($minuteKey); Redis::expire($minuteKey, 120); if ($minuteCount > $plan->requests_per_minute) { return RateLimitResult::exceeded( limit: $plan->requests_per_minute, reset: (floor(time() / 60) + 1) * 60 ); } // Monthly limit $monthKey = "rate:{$apiKey->id}:month:" . date('Y-m'); $monthCount = Redis::incr($monthKey); Redis::expireat($monthKey, strtotime('first day of next month')); if ($plan->requests_per_month !== -1 && $monthCount > $plan->requests_per_month) { return RateLimitResult::quotaExceeded($plan->requests_per_month); } return RateLimitResult::ok( remaining: $plan->requests_per_month === -1 ? null : $plan->requests_per_month - $monthCount ); } } אנו משתמשים בחלון נע עם הגדלה אטומית — זה מדויק יותר מחלון קבוע ואינו מוריד מגבלות בסוף הדקה. הפתרון של Redis מטפל בעד 100,000 בדיקות בשנייה — פי 100 מהר יותר מנעילות MySQL. כותרות התגובה כוללות user_id, class ApiKeyService { public function generate(int $userId, int $planId): array { $rawKey = 'sk_' . Str::random(48); // Пример: sk_A1B2C3D4... ApiKey::create([ 'user_id' => $userId, 'plan_id' => $planId, 'key_hash' => Hash::make($rawKey), 'key_prefix' => substr($rawKey, 0, 8), 'status' => 'active', ]); // Ключ показывается пользователю ОДИН РАЗ — после этого только хеш return ['key' => $rawKey, 'prefix' => substr($rawKey, 0, 8)]; } } ו-class ApiKeyAuthMiddleware { public function handle(Request $request, Closure $next): Response { $rawKey = $request->header('X-API-Key') ?? $request->bearerToken() ?? $request->query('api_key'); if (!$rawKey) { return response()->json(['error' => 'API key required'], 401); } // Быстрый поиск по префиксу, затем проверка хеша $prefix = substr($rawKey, 0, 8); $apiKey = ApiKey::where('key_prefix', $prefix)->where('status', 'active')->first(); if (!$apiKey || !Hash::check($rawKey, $apiKey->key_hash)) { return response()->json(['error' => 'Invalid API key'], 401); } $request->setApiKey($apiKey); return $next($request); } } . היישום שלנו משתמש באלגוריתם דלי אסימונים להאטה חלקה יותר.
מדוע הגבלת קצב ב-Redis מהירה יותר
נעילות MySQL (SELECT ... FOR UPDATE) יוצרות תורים ומאטות את התגובה בעומס גבוה. Redis עובד בזיכרון עם פעולות אטומיות — מספק זמן תגובה יציב ללא קשר למספר הבקשות המקבילות. עבור APIs עם אלפי RPM, זה קריטי.
לוח מחוונים לשימוש ב-API
הצגת רכיב לוח המחוונים
function ApiUsageDashboard({ apiKeyId }: Props) { const { data } = useQuery({ queryKey: ['api-usage', apiKeyId], queryFn: () => fetchUsageStats(apiKeyId), }); return ( <div className="grid grid-cols-3 gap-6"> <StatCard label="Запросов сегодня" value={data?.today} /> <StatCard label="Запросов в месяц" value={data?.month} limit={data?.monthLimit} /> <StatCard label="Среднее время (мс)" value={data?.avgResponseMs} /> </div> ); } משתמשים רואים בקשות שנותרו, זמן תגובה ממוצע (p95 מתחת ל-100 אלפיות שנייה) ויומן שיחות מפורט. זה מגביר אמון ומפחית בקשות תמיכה. לוח המחוונים מתעדכן בזמן אמת באמצעות Server-Sent Events.
תוכניות, תמחור ולוח זמנים לפרויקט
אפשרויות הגדרת תוכנית
התוכניות מוגדרות בטבלת class ApiRateLimiter { public function check(ApiKey $apiKey): RateLimitResult { $plan = $apiKey->plan; // Per-minute limit через Redis sliding window $minuteKey = "rate:{$apiKey->id}:minute:" . floor(time() / 60); $minuteCount = Redis::incr($minuteKey); Redis::expire($minuteKey, 120); if ($minuteCount > $plan->requests_per_minute) { return RateLimitResult::exceeded( limit: $plan->requests_per_minute, reset: (floor(time() / 60) + 1) * 60 ); } // Monthly limit $monthKey = "rate:{$apiKey->id}:month:" . date('Y-m'); $monthCount = Redis::incr($monthKey); Redis::expireat($monthKey, strtotime('first day of next month')); if ($plan->requests_per_month !== -1 && $monthCount > $plan->requests_per_month) { return RateLimitResult::quotaExceeded($plan->requests_per_month); } return RateLimitResult::ok( remaining: $plan->requests_per_month === -1 ? null : $plan->requests_per_month - $monthCount ); } } . כל השילובים נתמכים: מגבלות בקשות לדקה/חודש, גישה לנקודות קצה ספציפיות, תמחור לפי בקשה או מנויים קבועים. להלן דוגמת הגדרה (מעל 50 נקודות קצה זמינות):
| פרמטר | Starter | Business | Enterprise |
|---|---|---|---|
| בקשות בחודש | 10,000 | 100,000 | ללא הגבלה |
| בקשות בדקה | 60 | 600 | 6000 |
| נקודות קצה זמינות | /v1/public | + /v1/private | הכל |
| מחיר | $99/חודש | $499/חודש | מותאם אישית |
בעת יצירת תוכנית, ניתן לציין אילו נקודות קצה נגישות דרך שדה JSONB X-RateLimit-Limit.
שלבי יישום
תהליך היישום שלנו כולל את השלבים הבאים:
- עיצוב תוכנית והקמת מסד נתונים.
- יצירת מפתחות ו-middleware.
- הגבלת קצב עם Redis.
- שילוב לוח מחוונים.
- בדיקות ופריסה.
מה כלול בעבודה
| רכיב | תוצאה |
|---|---|
| מסד נתונים | דיאגרמת ER, מיגרציות Laravel, אינדקסים |
| מפתחות API | יצירה, גיבוב, middleware |
| הגבלת קצב | שירות Redis, כותרות X-RateLimit-* |
| לוח מחוונים | רכיב React עם תרשימים |
| אבטחה | HTTPS, CORS, אבטחת נתונים אישיים |
| תיעוד | OpenAPI/Swagger, דוגמאות curl |
| הדרכת צוות | הדגמה מקוונת של שעה |
רקורד שלנו
עם ניסיון של 10+ שנים ו-500+ פרויקטים מוצלחים, אנו שותף מהימן. במשך 5+ שנים בשוק, בנינו פתרונות לסטארטאפים ופלטפורמות פינטק כאחד. אנו מבטיחים: כל המפתחות מגובבים, המגבלות פועלות ללא שגיאות, לוח המחוונים מוגש תוך 200 אלפיות שנייה. כל פרויקט מלווה בתיעוד והדרכת צוות.
צרו קשר — נעריך את הפרויקט שלכם תוך יום עסקים אחד. אנחנו לא מוכרים פתרונות מוכנים: כל ארכיטקטורה מותאמת לתרחישים שלכם.
לוחות זמנים ועלות
יישום מפתח (תוכניות, מפתחות, הגבלת קצב, לוח מחוונים) — 8–12 ימי עסקים. המורכבות ולוח הזמנים מובהרים בפגישה. העלות מתחילה מ-$4,500 להתקנה בסיסית ומחושבת באופן אישי לפי הדרישות שלכם.
הזמינו אינטגרציה — והתחילו להרוויח מה-API שלכם תוך שבועיים בלבד.







