Documentation Index
Fetch the complete documentation index at: https://docs.galxe.com/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Implement quest systems that handle:
- Quest validation and status checking
- User eligibility verification through credential groups
- Quest discovery and filtering
- Loyalty points tracking
Basic Quest Operations
Get Quest Details
query GetQuest($id: ID!) {
quest(id: $id) {
id
name
type
status
description
startTime
endTime
cap
participantsCount
loyaltyPoints
space {
id
name
}
chain
}
}
Response:
{
"data": {
"quest": {
"id": "GChdWUjXX3",
"name": "Introduction to Web3!",
"type": "Drop",
"status": "Active",
"description": "Welcome to Module 1-Course 1 of Mission Web3!",
"startTime": 1699200000,
"endTime": 1699800000,
"cap": 10000,
"participantsCount": 234163,
"loyaltyPoints": 100,
"space": {
"id": "40",
"name": "BNB Chain"
},
"chain": "BSC"
}
}
}
List Space Quests
query GetSpaceQuests($spaceId: ID!, $first: Int!, $statuses: [QuestStatus!]) {
quests(input: {
spaceId: $spaceId
first: $first
statuses: $statuses
}) {
totalCount
pageInfo {
hasNextPage
endCursor
}
list {
id
name
type
status
participantsCount
loyaltyPoints
startTime
endTime
}
}
}
Quest Status Reference
| Status | Description | When Used |
|---|
Draft | Quest in development | Before publishing |
Active | Quest is live and accepting participants | During quest period |
NotStarted | Quest published but not started | Before start time |
Expired | Quest has ended | After end time |
CapReached | Participant limit reached | When cap is full |
Deleted | Quest removed | Removed quests |
Quest Types
| Type | Description |
|---|
Drop | NFT drop quest |
MysteryBox | Mystery box reward |
Airdrop | Token airdrop |
Points | Loyalty points reward |
ExternalLink | External link verification |
Bounty | Bounty quest |
User Eligibility Verification
Check User Eligibility
query CheckUserEligibility($questId: ID!, $address: String!) {
quest(id: $questId) {
id
name
status
credentialGroups(address: $address) {
id
name
conditionRelation
conditions {
expression
eligible
}
rewards {
expression
eligible
rewardType
rewardCount
}
}
}
}
Key Points:
- When
conditions.eligible is true, user meets requirements
- When
rewards.eligible is true, user can claim rewards
conditionRelation can be ALL (must meet all) or ANY (meet at least one)
Basic Implementation
Quest Validation
async function validateQuest(questId, accessToken) {
const response = await fetch('https://graphigo-business.prd.galaxy.eco/query', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'access-token': accessToken
},
body: JSON.stringify({
query: `query GetQuest($id: ID!) {
quest(id: $id) {
id
name
status
startTime
endTime
participantsCount
cap
}
}`,
variables: { id: questId }
})
});
const data = await response.json();
const quest = data.data.quest;
if (!quest) throw new Error('Quest not found');
// Check quest status
if (quest.status === 'Draft') throw new Error('Quest is in draft mode');
if (quest.status === 'Deleted') throw new Error('Quest has been deleted');
if (quest.status === 'Expired') throw new Error('Quest has expired');
if (quest.status === 'CapReached') throw new Error('Quest capacity reached');
// Check timing for active quests
if (quest.status === 'Active' && quest.startTime && quest.endTime) {
const now = Math.floor(Date.now() / 1000);
if (now < quest.startTime) throw new Error('Quest has not started yet');
if (now > quest.endTime) throw new Error('Quest has ended');
}
return quest;
}
Check User Eligibility
async function checkUserEligibility(questId, userAddress, accessToken) {
const response = await fetch('https://graphigo-business.prd.galaxy.eco/query', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'access-token': accessToken
},
body: JSON.stringify({
query: `query CheckUserEligibility($questId: ID!, $address: String!) {
quest(id: $questId) {
id
name
status
credentialGroups(address: $address) {
id
name
conditionRelation
conditions {
expression
eligible
}
rewards {
expression
eligible
rewardType
rewardCount
}
}
}
}`,
variables: { questId, address: userAddress }
})
});
const data = await response.json();
const quest = data.data.quest;
if (!quest) throw new Error('Quest not found');
const eligibilityResults = quest.credentialGroups.map(group => {
// Check conditions based on relation (ALL or ANY)
const conditionsMet = group.conditionRelation === 'ALL'
? group.conditions.every(c => c.eligible)
: group.conditions.some(c => c.eligible);
const eligibleRewards = group.rewards.filter(r => r.eligible);
return {
groupId: group.id,
groupName: group.name,
conditionsMet,
eligibleRewards
};
});
const isEligible = eligibilityResults.some(r => r.conditionsMet && r.eligibleRewards.length > 0);
return {
questId,
userAddress,
isEligible,
eligibilityDetails: eligibilityResults,
questName: quest.name,
questStatus: quest.status
};
}
Get Space Quests
async function getSpaceQuests(spaceId, accessToken, options = {}) {
const {
limit = 20,
cursor = null,
statuses = ['Active']
} = options;
const response = await fetch('https://graphigo-business.prd.galaxy.eco/query', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'access-token': accessToken
},
body: JSON.stringify({
query: `query GetSpaceQuests($input: ListQuestInput!) {
quests(input: $input) {
totalCount
pageInfo {
hasNextPage
endCursor
}
list {
id
name
type
status
participantsCount
loyaltyPoints
startTime
endTime
cap
}
}
}`,
variables: {
input: {
spaceId,
first: limit,
after: cursor,
statuses
}
}
})
});
const data = await response.json();
return data.data.quests;
}
Quest Status Helpers
Check Quest Phase
function getQuestPhase(quest) {
switch (quest.status) {
case 'NotStarted':
return 'not_started';
case 'Active':
if (quest.startTime && quest.endTime) {
const now = Math.floor(Date.now() / 1000);
if (now < quest.startTime) return 'scheduled';
if (now > quest.endTime) return 'ended_pending';
}
return 'active';
case 'Expired':
return 'expired';
case 'CapReached':
return 'full';
case 'Draft':
return 'draft';
case 'Deleted':
return 'deleted';
default:
return 'unknown';
}
}
function isQuestParticipable(quest) {
if (quest.status !== 'Active') return false;
// Check capacity
if (quest.cap > 0 && quest.participantsCount >= quest.cap) return false;
// Check timing
if (quest.startTime && quest.endTime) {
const now = Math.floor(Date.now() / 1000);
if (now < quest.startTime || now > quest.endTime) return false;
}
return true;
}
Usage Examples
Basic Quest Validation
// Validate quest before showing UI
const accessToken = process.env.GALXE_ACCESS_TOKEN;
try {
const quest = await validateQuest('GChdWUjXX3', accessToken);
console.log(`Quest "${quest.name}" is ${quest.status}`);
console.log(`Participants: ${quest.participantsCount}`);
const phase = getQuestPhase(quest);
const canParticipate = isQuestParticipable(quest);
console.log(`Phase: ${phase}`);
console.log(`Can participate: ${canParticipate}`);
} catch (error) {
console.error('Quest validation failed:', error.message);
}
User Eligibility Check
// Check if user can participate
const userAddress = '0x1234567890123456789012345678901234567890';
const eligibility = await checkUserEligibility('GChdWUjXX3', userAddress, accessToken);
if (eligibility.isEligible) {
console.log('User is eligible for quest');
console.log('Available rewards:', eligibility.eligibilityDetails
.flatMap(group => group.eligibleRewards)
.map(reward => reward.expression)
);
} else {
console.log('User is not eligible for this quest');
console.log('Missing requirements:', eligibility.eligibilityDetails
.filter(group => !group.conditionsMet)
.map(group => group.groupName)
);
}
Quest Discovery
// Get active quests for a space
const spaceQuests = await getSpaceQuests('40', accessToken, {
statuses: ['Active'],
limit: 10
});
console.log(`Found ${spaceQuests.totalCount} active quests`);
console.log('Quest list:');
spaceQuests.list.forEach(quest => {
console.log(`- ${quest.name} (${quest.loyaltyPoints} points, ${quest.participantsCount} participants)`);
});
Complete Quest Check
async function createQuestDashboard(spaceId, userAddress, accessToken) {
// Get active quests
const quests = await getSpaceQuests(spaceId, accessToken, {
statuses: ['Active'],
limit: 10
});
// Check eligibility for top quests
const eligibilityChecks = await Promise.all(
quests.list.slice(0, 5).map(quest =>
checkUserEligibility(quest.id, userAddress, accessToken)
.then(result => ({ ...quest, eligibility: result }))
.catch(error => ({ ...quest, eligibility: { error: error.message } }))
)
);
const eligibleQuests = eligibilityChecks.filter(q => q.eligibility.isEligible);
const totalPoints = eligibleQuests.reduce((sum, q) => sum + q.loyaltyPoints, 0);
return {
space: { id: spaceId },
totalQuests: quests.totalCount,
checkedQuests: eligibilityChecks.length,
eligibleQuests: eligibleQuests.length,
potentialPoints: totalPoints,
quests: eligibilityChecks
};
}
Best Practices
- Status Validation: Always check quest status before showing participation UI
- Error Handling: Handle cases where quests are not found or access is denied
- Rate Limiting: Add delays when processing multiple quests or users
- Caching: Cache quest details for 1-5 minutes to reduce API calls
- Capacity Monitoring: Check both status and participant count vs cap
Quest Lifecycle
| Status | User Actions | Next Status |
|---|
Draft | None (not visible) | NotStarted or Active |
NotStarted | View details, set reminders | Active |
Active | Participate, check eligibility | Expired or CapReached |
CapReached | View results only | Expired |
Expired | View results only | N/A |
Deleted | None (hidden) | N/A |
Common Integration Patterns
- Quest Discovery: Filter by space, status, and type
- Eligibility Pre-check: Verify user can participate before showing UI
- Status Monitoring: Track quest lifecycle changes
- Reward Tracking: Monitor available rewards and claim status
- Points Calculation: Track potential loyalty points earnings
Next Steps