CodeBlanks'i kendi ürününe bağla
Kullanıcılarını CodeBlanks hesabıyla giriş yaptır, öğrenme ilerlemelerini (XP, rozet, sertifika) API ile oku, olayları webhook ile anında al.
Giriş yap ve başlaGenel bakış
Üç yol var; ihtiyacına göre birini ya da hepsini kullan:
Kimlik doğrulama
Her istekte Authorization başlığında bir kimlik gönder. İki tür kimlik geçerli:
- Kişisel API anahtarı (cbk_ ile başlar): Panel > Geliştirici bölümünden oluşturulur, kendi hesabının verisini okur.
- OAuth erişim token'ı: "CodeBlanks ile giriş" ile alınır, izin veren kullanıcının verisini, verdiği kapsamlar kadar okur.
curl -H "Authorization: Bearer cbk_…" https://codeblanks.com/api/v1/me Anahtarları ve secret'ları yalnızca sunucuda tut; tarayıcıya ya da mobil uygulama paketine koyma.
Kapsamlar
Bir anahtar ya da token yalnızca sahip olduğu kapsamların uç noktalarını çağırabilir.
- profile: ad, kullanıcı adı, avatar, profil bağlantısı, XP
- email: e-posta adresi
- progress: XP, rütbe, seri, rozetler, sertifikalar
Uç noktalar
Tüm uç noktalar salt okunur (GET) ve JSON döner. Başarılı yanıt "data", hata "error" alanında gelir. ?lang=tr|en ile rozet ve rütbe adlarının dilini seçebilirsin.
https://codeblanks.com/api/v1
| İstek | Kapsam | Açıklama |
|---|---|---|
GET /me |
profile |
Giriş yapan kullanıcının profili. email kapsamı varsa e-posta da gelir. |
GET /me/progress |
progress |
XP, rütbe, seri, tamamlanan kurs sayısı, rozetler ve sertifikalar. |
GET /users/{username} |
profile |
Herhangi bir kullanıcının herkese açık profili. |
GET /users/{username}/badges |
profile |
Kullanıcının kazandığı rozetler. |
GET /certificates/{code} |
herhangi | Sertifika doğrulama: kod geçerliyse sahibi ve kursu döner. |
Örnek istek
curl -H "Authorization: Bearer cbk_…" "https://codeblanks.com/api/v1/me/progress?lang=tr" Örnek yanıt
{
"data": {
"xp": 1840,
"rank": {
"current": { "id": 3, "name": "Kod Çırağı", "min_xp": 1000 },
"next": { "id": 4, "name": "Geliştirici", "min_xp": 2500 }
},
"streak": { "current": 6, "longest": 21, "last_activity": "2026-10-13" },
"courses_completed": 2,
"badges": [
{ "id": 12, "key": "lessons_completed_10", "name": "10 ders", "icon": "fas fa-book", "color": "#0D9488", "xp_reward": 50, "earned_at": "2026-10-02T14:11:09+03:00" }
],
"certificates": [
{ "code": "CB-1A2B-3C4D-5E6F", "course_id": 4, "course_title": "PHP Temelleri", "issued_at": "2026-09-28T10:00:00+03:00", "verify_url": "https://codeblanks.com/api/v1/certificates/CB-1A2B-3C4D-5E6F" }
]
}
} Hız sınırı ve hatalar
Anahtar / token başına dakikada 60 istek. Her yanıtta X-RateLimit-Limit, X-RateLimit-Remaining ve X-RateLimit-Reset başlıkları gelir; sınır aşılınca 429 ve Retry-After döner.
401 |
Kimlik yok, geçersiz, süresi dolmuş ya da iptal edilmiş. |
403 |
Kapsam yetersiz (insufficient_scope) ya da hesap askıya alınmış. |
404 |
Kullanıcı, sertifika ya da uç nokta bulunamadı. |
429 |
Hız sınırı aşıldı. |
503 |
API geçici olarak kapalı. |
{ "error": { "code": "insufficient_scope", "message": "This credential does not have the \"progress\" scope." } } "CodeBlanks ile giriş" ekle
Standart OAuth 2.0 yetki kodu akışı + PKCE (S256, zorunlu) + OpenID Connect. Hazır bir OAuth / OIDC kütüphanesi keşif adresini vermen yeterli olacak şekilde çalışır.
- Panel > Geliştirici > Uygulamalarım bölümünden uygulama oluştur; client_id ve client secret'ı al, dönüş adresini kaydet.
- Kullanıcıyı yetki adresine gönder (response_type=code, client_id, redirect_uri, scope, state, code_challenge, code_challenge_method=S256).
- Kullanıcı onaylayınca dönüş adresine ?code=…&state=… ile gelir; state'i doğrula.
- Kodu sunucundan token adresine gönder (grant_type=authorization_code, code, redirect_uri, code_verifier, client kimliği). access_token, refresh_token ve id_token gelir.
- id_token'ı JWKS ile doğrula ya da access_token ile userinfo / API çağır. Kullanıcıyı "sub" (CodeBlanks kullanıcı kimliği) ile eşleştir.
Adresler
| Keşif belgesi | https://codeblanks.com/.well-known/openid-configuration |
| Yetki | https://codeblanks.com/oauth/authorize |
| Token | POST https://codeblanks.com/oauth/token |
| Kullanıcı bilgisi | https://codeblanks.com/oauth/userinfo |
| İmza anahtarları (JWKS) | https://codeblanks.com/oauth/jwks.json |
| Token iptali | POST https://codeblanks.com/oauth/revoke |
Erişim token'ı 1 saat, yenileme token'ı 30 gün geçerli. Yenileme token'ı her kullanımda değişir; eskisi tekrar kullanılırsa o oturumun tüm token'ları iptal edilir.
PHP örneği (league/oauth2-client)
$provider = new \League\OAuth2\Client\Provider\GenericProvider([
'clientId' => 'cb_…',
'clientSecret' => 'cbs_…',
'redirectUri' => 'https://liyakat.net/auth/codeblanks/callback',
'urlAuthorize' => 'https://codeblanks.com/oauth/authorize',
'urlAccessToken' => 'https://codeblanks.com/oauth/token',
'urlResourceOwnerDetails' => 'https://codeblanks.com/oauth/userinfo',
'scopes' => 'openid profile email progress',
'scopeSeparator' => ' ',
'pkceMethod' => \League\OAuth2\Client\Provider\GenericProvider::PKCE_METHOD_S256,
]);
// 1) Giriş düğmesi
if (!isset($_GET['code'])) {
$url = $provider->getAuthorizationUrl();
$_SESSION['oauth2state'] = $provider->getState();
$_SESSION['oauth2pkce'] = $provider->getPkceCode();
header('Location: ' . $url);
exit;
}
// 2) Dönüş
if (!hash_equals($_SESSION['oauth2state'] ?? '', $_GET['state'] ?? '')) {
exit('Invalid state');
}
$provider->setPkceCode($_SESSION['oauth2pkce']);
$token = $provider->getAccessToken('authorization_code', ['code' => $_GET['code']]);
$user = $provider->getResourceOwner($token)->toArray(); // sub, preferred_username, name, email …
// 3) API: XP ve rozetler
$req = $provider->getAuthenticatedRequest('GET', 'https://codeblanks.com/api/v1/me/progress', $token);
$progress = json_decode((string) $provider->getResponse($req)->getBody(), true)['data']; Webhook'lar
Panel > Geliştirici > Webhook'lar bölümünden adres ve olayları seç. Kişisel webhook yalnızca senin olaylarını alır; uygulamana bağlı webhook, uygulamana "progress" izni veren tüm kullanıcıların olaylarını alır.
Olaylar
badge.earned |
Rozet kazanıldı | progress |
course.completed |
Kurs tamamlandı | progress |
certificate.issued |
Sertifika verildi | progress |
rank.changed |
Rütbe atlandı | progress |
Başlıklar
POST /webhooks/codeblanks HTTP/1.1
Content-Type: application/json
User-Agent: CodeBlanks-Webhooks/1.0
X-CodeBlanks-Event: badge.earned
X-CodeBlanks-Delivery: 9f0c…
X-CodeBlanks-Signature: t=1791880000,v1=5d41402abc4b2a76b9719d911017c592… Gövde
{
"id": "evt_9f0c2b7e4d1a4c0b8e6f3a2d1c0b9a87",
"type": "badge.earned",
"created": 1791880000,
"data": {
"user": { "id": 42, "username": "murat", "profile_url": "https://codeblanks.com/@murat" },
"badge": { "id": 12, "key": "lessons_completed_10", "name": "10 ders", "icon": "fas fa-book", "xp_reward": 50 }
}
} İmzayı doğrula
X-CodeBlanks-Signature başlığı t=<zaman>,v1=<imza> biçimindedir. imza = HMAC-SHA256(imza anahtarı, "<t>.<ham gövde>"). Zamanı 5 dakikadan eskiyse isteği reddet; aynı X-CodeBlanks-Delivery'yi ikinci kez işleme.
$body = file_get_contents('php://input');
$header = $_SERVER['HTTP_X_CODEBLANKS_SIGNATURE'] ?? '';
parse_str(str_replace(',', '&', $header), $sig); // ['t' => …, 'v1' => …]
$expected = hash_hmac('sha256', ($sig['t'] ?? '') . '.' . $body, getenv('CODEBLANKS_WEBHOOK_SECRET'));
if (!hash_equals($expected, $sig['v1'] ?? '') || abs(time() - (int) ($sig['t'] ?? 0)) > 300) {
http_response_code(400);
exit;
}
http_response_code(204); // hemen dön, işi kuyruğa at
$event = json_decode($body, true); // Node.js (Express): gövdeyi ham haliyle al
app.post('/webhooks/codeblanks', express.raw({ type: 'application/json' }), (req, res) => {
const sig = Object.fromEntries(req.get('X-CodeBlanks-Signature').split(',').map(p => p.split('=')));
const expected = crypto.createHmac('sha256', process.env.CODEBLANKS_WEBHOOK_SECRET)
.update(sig.t + '.' + req.body).digest('hex');
const a = Buffer.from(expected), b = Buffer.from(sig.v1 || '');
const ok = a.length === b.length && crypto.timingSafeEqual(a, b);
if (!ok || Math.abs(Date.now() / 1000 - Number(sig.t)) > 300) return res.sendStatus(400);
res.sendStatus(204);
const event = JSON.parse(req.body);
}); 2xx dışında bir yanıt ya da zaman aşımı (5 sn) başarısız sayılır ve tekrar denenir: 1 dk, 5 dk, 30 dk, 2 sa, 6 sa, 24 sa. Art arda çok başarısız teslim olursa webhook kapanır. Hemen 2xx dön, işi arka planda yap.
Destek
Soru ya da hata bildirimi için iletişim sayfasını kullan. İletişim