sk_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p4X-API-Key: sk_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p4GET /api/v1/classes/{classId}/students/{studentCode}파라미터 | 타입 | 설명 | 예시 |
classId | string | 클래스 ID (그라운드에서 확인) | NP0hetJ3wyQKFtRnFeftmPiy8Dl4_2 |
studentCode | number | 학생 번호 (출석번호) | 2 |
헤더 | 값 | 필수 |
X-API-Key | 발급받은 API 키 | ✅ |
curl -X GET \
"https://growndcard.com/api/v1/classes/NP0hetJ3wyQKFtRnFeftmPiy8Dl4_2/students/2" \
-H "X-API-Key: sk_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p4"{
"success": true,
"data": {
"studentId": "stu_abc123",
"studentCode": 2,
"studentName": "홍길동",
"avatar": "/avatars/a1.png",
"points": {
"totalPoints": 150,
"rewardPoints": 180,
"penaltyPoints": 30,
"currentLevel": 4,
"levelName": "아스파라거스"
},
"dragon": {
"name": "불꽃이",
"stage": "baby",
"level": 3,
"absoluteLevel": 8,
"experience": 45,
"food": 12,
"color": "red",
"heartstones": 5
},
"marketInventory": {
"totalItems": 12,
"regularMarket": {
"totalCount": 5,
"products": [
{
"productName": "연필 세트",
"productEmoji": "✏️"
},
{
"productName": "지우개",
"productEmoji": "🧹"
}
]
},
"commonMarket": {
"totalCount": 4,
"products": [
{
"productName": "간식 세트",
"productEmoji": "🍪"
}
]
},
"cave": {
"totalCount": 3,
"products": [
{
"productName": "드래곤 먹이",
"productEmoji": "🥩"
}
]
}
},
"farmItems": {
"heartBerries": 25,
"placedItems": [
{
"itemId": "item_001",
"name": "분수",
"emoji": "⛲",
"x": 2,
"y": 3
},
{
"itemId": "item_002",
"name": "나무",
"emoji": "🌳",
"x": 4,
"y": 2
}
],
"inventoryItems": [
{
"itemId": "item_003",
"name": "꽃",
"emoji": "🌸",
"quantity": 5
},
{
"itemId": "item_004",
"name": "벤치",
"emoji": "🪑",
"quantity": 2
}
],
"farmBackground": "spring",
"placedItemBonusPoints": 2.5
}
},
"message": "학생 정보 조회에 성공했습니다."
}필드 | 타입 | 설명 | 예시 |
studentId | string | 학생의 내부 ID | "stu_abc123" |
studentCode | number | 학생 번호 (출석번호) | 2 |
studentName | string | 학생 이름 | "홍길동" |
avatar | string | 아바타 이미지 경로 | "/avatars/a1.png" |
필드 | 타입 | 설명 | 범위 |
totalPoints | number | 총 포인트 (리워드 - 페널티) | - |
rewardPoints | number | 누적 리워드 포인트 | >= 0 |
penaltyPoints | number | 누적 페널티 포인트 | >= 0 |
currentLevel | number | 현재 레벨 | 1-50 |
levelName | string | 레벨 명칭 | "아몬드" 등 (식물 이름) |
필드 | 타입 | 설명 | 값 |
name | string | 드래곤 이름 (베이비 단계부터 설정 가능) | "불꽃이" |
stage | string | 드래곤 단계 | egg, baby, junior, strong, super |
level | number | 단계별 레벨 | 1-5 |
absoluteLevel | number | 절대 레벨 (전체 진행도) | 0-25 |
experience | number | 현재 경험치 | >= 0 |
food | number | 보유 먹이 개수 | >= 0 |
color | string | 드래곤 색상 | red, blue, green 등 |
heartstones | number | 보유 하트스톤 개수 | >= 0 |
필드 | 타입 | 설명 |
totalItems | number | 전체 구매 기록 개수 (3가지 마켓 타입의 총합) |
regularMarket | object | 일반 마켓 상품 정보 |
commonMarket | object | 공동구매 상품 정보 |
cave | object | 케이브 (드래곤 동굴) 상품 정보 |
필드 | 타입 | 설명 |
totalCount | number | 해당 마켓 타입의 상품 개수 |
products | array | 보유 중인 상품 목록 (중복 제거됨) |
필드 | 타입 | 설명 |
productName | string | 상품 이름 |
productEmoji | string | 상품 이모지 (선택) |
필드 | 타입 | 설명 |
heartBerries | number | 보유 하트베리 개수 |
placedItems | array | 텃밭에 배치된 아이템 목록 |
inventoryItems | array | 인벤토리 아이템 목록 (수량 포함) |
farmBackground | string | 텃밭 배경 |
placedItemBonusPoints | number | 배치 아이템의 포인트 보너스 합계 |
{
itemId: string; // 아이템 ID
name: string; // 아이템 이름
emoji: string; // 아이템 이모지
x: number; // X 좌표
y: number; // Y 좌표
}{
itemId: string; // 아이템 ID
name: string; // 아이템 이름
emoji: string; // 아이템 이모지
quantity: number; // 보유 수량
}{
"success": false,
"error": {
"code": "error_code",
"message": "에러 메시지",
"details": {}
}
}상태 코드 | 에러 코드 | 설명 | 해결 방법 |
400 | invalid_student_code | 학생 번호가 제공되지 않음 | studentCode 확인 |
401 | unauthorized | API 키가 없거나 유효하지 않음 | API 키 확인, X-API-Key 헤더 확인 |
403 | forbidden | 해당 클래스 접근 권한 없음 | classId 확인 |
403 | insufficient_permissions | 학생 조회 권한이 없음 | API 키의 readStudents 권한 확인 |
404 | student_not_found | 학생을 찾을 수 없음 | studentCode 확인 |
429 | rate_limit_exceeded | 호출 제한 초과 | 잠시 후 재시도 |
500 | internal_error | 서버 내부 오류 | 잠시 후 재시도, 반복되면 문의 |
{
"success": false,
"error": {
"code": "insufficient_permissions",
"message": "학생 정보 조회 권한이 없습니다.",
"details": {
"requiredPermission": "readStudents"
}
}
}curl -X GET \
"https://growndcard.com/api/v1/classes/NP0hetJ3wyQKFtRnFeftmPiy8Dl4_2/students/2" \
-H "X-API-Key: sk_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p4"const fetch = require('node-fetch');
const API_KEY = 'sk_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p4';
const BASE_URL = 'https://growndcard.com';
const CLASS_ID = 'NP0hetJ3wyQKFtRnFeftmPiy8Dl4_2';
async function getStudentInfo(studentCode) {
try {
const response = await fetch(
`${BASE_URL}/api/v1/classes/${CLASS_ID}/students/${studentCode}`,
{
method: 'GET',
headers: {
'X-API-Key': API_KEY
}
}
);
const data = await response.json();
if (!response.ok) {
throw new Error(`API Error: ${data.error.message}`);
}
console.log('학생 정보 조회 성공:', data.data);
return data.data;
} catch (error) {
console.error('학생 정보 조회 실패:', error.message);
throw error;
}
}
// 사용 예시
getStudentInfo(2)
.then(student => {
console.log(`학생: ${student.studentName}`);
console.log(`총 포인트: ${student.points.totalPoints}`);
console.log(`레벨: ${student.points.currentLevel} (${student.points.levelName})`);
if (student.dragon) {
console.log(`드래곤: ${student.dragon.name || '이름 없음'} (Lv.${student.dragon.absoluteLevel})`);
}
console.log(`보유 상품 수: ${student.marketProducts.length}개`);
console.log(`하트베리: ${student.farmItems.heartBerries}개`);
})
.catch(error => console.error('에러:', error));import requests
import json
API_KEY = 'sk_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p4'
BASE_URL = 'https://growndcard.com'
CLASS_ID = 'NP0hetJ3wyQKFtRnFeftmPiy8Dl4_2'
def get_student_info(student_code):
"""학생 정보 조회"""
url = f'{BASE_URL}/api/v1/classes/{CLASS_ID}/students/{student_code}'
headers = {
'X-API-Key': API_KEY
}
try:
response = requests.get(url, headers=headers)
response.raise_for_status()
data = response.json()
print(f"학생 정보 조회 성공: {data['data']}")
return data['data']
except requests.exceptions.HTTPError as e:
error_data = response.json()
print(f"API 에러: {error_data['error']['message']}")
raise
except Exception as e:
print(f"요청 실패: {str(e)}")
raise
# 사용 예시
if __name__ == '__main__':
student = get_student_info(2)
print(f"학생: {student['studentName']}")
print(f"총 포인트: {student['points']['totalPoints']}")
print(f"레벨: {student['points']['currentLevel']} ({student['points']['levelName']})")
if student['dragon']:
dragon_name = student['dragon'].get('name', '이름 없음')
print(f"드래곤: {dragon_name} (Lv.{student['dragon']['absoluteLevel']})")
print(f"전체 마켓 상품: {student['marketInventory']['totalItems']}개")
print(f"일반 마켓: {student['marketInventory']['regularMarket']['totalCount']}개")
print(f"하트베리: {student['farmItems']['heartBerries']}개")interface StudentInfoResponse {
success: boolean;
data?: {
studentId: string;
studentCode: number;
studentName: string;
avatar?: string;
points: {
totalPoints: number;
rewardPoints: number;
penaltyPoints: number;
currentLevel: number;
levelName: string;
};
dragon: {
name?: string;
stage: string;
level: number;
absoluteLevel: number;
experience: number;
food: number;
color?: string;
heartstones: number;
} | null;
marketInventory: {
totalItems: number;
regularMarket: {
totalCount: number;
products: Array<{
productName: string;
productEmoji?: string;
}>;
};
commonMarket: {
totalCount: number;
products: Array<{
productName: string;
productEmoji?: string;
}>;
};
cave: {
totalCount: number;
products: Array<{
productName: string;
productEmoji?: string;
}>;
};
};
farmItems: {
heartBerries: number;
placedItems: Array<{
itemId: string;
name: string;
emoji: string;
x: number;
y: number;
}>;
inventoryItems: Array<{
itemId: string;
name: string;
emoji: string;
quantity?: number;
}>;
farmBackground?: string;
placedItemBonusPoints?: number;
};
};
message?: string;
}
class GroundStudentApiClient {
private apiKey: string;
private baseUrl: string;
private classId: string;
constructor(apiKey: string, classId: string) {
this.apiKey = apiKey;
this.classId = classId;
this.baseUrl = 'https://growndcard.com';
}
async getStudentInfo(studentCode: number): Promise<StudentInfoResponse> {
const url = `${this.baseUrl}/api/v1/classes/${this.classId}/students/${studentCode}`;
const response = await fetch(url, {
method: 'GET',
headers: {
'X-API-Key': this.apiKey
}
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.error?.message || 'API 호출 실패');
}
return data;
}
}
// 사용 예시
const client = new GroundStudentApiClient(
'sk_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6',
'NP0hetJ3wyQKFtRnFeftmPiy8Dl2_2'
);
async function example() {
try {
const result = await client.getStudentInfo(2);
const student = result.data;
if (!student) return;
console.log(`학생: ${student.studentName}`);
console.log(`총 포인트: ${student.points.totalPoints}`);
console.log(`레벨: ${student.points.currentLevel} (${student.points.levelName})`);
if (student.dragon) {
console.log(`드래곤: ${student.dragon.name || '이름 없음'} (Lv.${student.dragon.absoluteLevel})`);
console.log(`먹이: ${student.dragon.food}개, 경험치: ${student.dragon.experience}`);
}
console.log(`전체 마켓 상품: ${student.marketInventory.totalItems}개`);
console.log(`일반 마켓: ${student.marketInventory.regularMarket.totalCount}개`);
console.log(`공동구매: ${student.marketInventory.commonMarket.totalCount}개`);
console.log(`케이브: ${student.marketInventory.cave.totalCount}개`);
console.log(`하트베리: ${student.farmItems.heartBerries}개`);
console.log(`배치 아이템: ${student.farmItems.placedItems.length}개`);
console.log(`인벤토리 아이템: ${student.farmItems.inventoryItems.length}종류`);
} catch (error) {
console.error('학생 정보 조회 실패:', error);
}
}<?php
function getStudentInfo($studentCode) {
$apiKey = 'sk_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p4';
$classId = 'NP0hetJ3wyQKFtRnFeftmPiy8Dl4_2';
$baseUrl = 'https://growndcard.com';
$url = "{$baseUrl}/api/v1/classes/{$classId}/students/{$studentCode}";
$options = [
'http' => [
'method' => 'GET',
'header' => [
"X-API-Key: {$apiKey}"
]
]
];
$context = stream_context_create($options);
$response = file_get_contents($url, false, $context);
if ($response === false) {
throw new Exception('API 호출 실패');
}
$result = json_decode($response, true);
if (!$result['success']) {
throw new Exception($result['error']['message']);
}
return $result['data'];
}
// 사용 예시
try {
$student = getStudentInfo(2);
echo "학생: {$student['studentName']}\n";
echo "총 포인트: {$student['points']['totalPoints']}\n";
echo "레벨: {$student['points']['currentLevel']} ({$student['points']['levelName']})\n";
if ($student['dragon']) {
$dragonName = $student['dragon']['name'] ?? '이름 없음';
echo "드래곤: {$dragonName} (Lv.{$student['dragon']['absoluteLevel']})\n";
}
echo "전체 마켓 상품: {$student['marketInventory']['totalItems']}개\n";
echo "일반 마켓: {$student['marketInventory']['regularMarket']['totalCount']}개\n";
echo "하트베리: {$student['farmItems']['heartBerries']}개\n";
} catch (Exception $e) {
echo "에러: " . $e->getMessage() . "\n";
}