Create a Discord Balance Manager to search by Discord ID and manage point balances π°
Get Your API Key
Choose Your Weapon
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DRIP Balance Manager π°</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 20px;
}
.container {
max-width: 800px;
margin: 0 auto;
background: white;
border-radius: 20px;
box-shadow: 0 20px 40px rgba(0,0,0,0.1);
overflow: hidden;
}
.header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 30px;
text-align: center;
}
.header h1 {
font-size: 2.5em;
margin-bottom: 10px;
}
.content {
padding: 30px;
}
.search-section {
background: #f8f9ff;
padding: 25px;
border-radius: 15px;
margin-bottom: 30px;
}
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: block;
margin-bottom: 8px;
font-weight: 600;
color: #333;
}
.form-group input, .form-group textarea, .form-group select {
width: 100%;
padding: 12px 15px;
border: 2px solid #e1e5e9;
border-radius: 10px;
font-size: 16px;
transition: border-color 0.3s;
}
.form-group input:focus, .form-group textarea:focus, .form-group select:focus {
outline: none;
border-color: #667eea;
}
.btn {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
padding: 12px 25px;
border-radius: 10px;
font-size: 16px;
font-weight: 600;
cursor: pointer;
transition: transform 0.2s;
margin-right: 10px;
margin-bottom: 10px;
}
.btn:hover {
transform: translateY(-2px);
}
.btn.success {
background: #28a745;
}
.btn.danger {
background: #dc3545;
}
.user-card {
background: #f8f9ff;
padding: 25px;
border-radius: 15px;
margin-bottom: 20px;
border-left: 5px solid #667eea;
}
.user-info {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.user-details h3 {
color: #333;
margin-bottom: 5px;
}
.user-details p {
color: #666;
margin: 2px 0;
}
.balance-list {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
margin-bottom: 20px;
}
.balance-item {
background: white;
padding: 15px;
border-radius: 10px;
text-align: center;
border: 2px solid #e1e5e9;
}
.balance-amount {
font-size: 1.5em;
font-weight: bold;
color: #667eea;
}
.balance-name {
font-size: 0.9em;
color: #666;
margin-top: 5px;
}
.balance-actions {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 15px;
margin-top: 20px;
}
.loading {
text-align: center;
padding: 40px;
color: #666;
}
.error {
background: #f8d7da;
color: #721c24;
padding: 15px;
border-radius: 10px;
margin-bottom: 20px;
border-left: 5px solid #dc3545;
}
.success {
background: #d4edda;
color: #155724;
padding: 15px;
border-radius: 10px;
margin-bottom: 20px;
border-left: 5px solid #28a745;
}
.hidden {
display: none;
}
@media (max-width: 768px) {
.user-info {
flex-direction: column;
align-items: flex-start;
}
.balance-actions {
grid-template-columns: 1fr;
}
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>π° Balance Manager</h1>
<p>Search and manage member point balances</p>
</div>
<div class="content">
<!-- Search Section -->
<div class="search-section">
<h2>π Find Member by Discord ID</h2>
<div class="form-group">
<label for="discordId">Discord User ID</label>
<input type="text" id="discordId" placeholder="e.g., 123456789012345678">
<small style="color: #666; font-size: 0.9em;">Right-click a user in Discord β Copy User ID</small>
</div>
<button class="btn" onclick="searchUser()">Search Member</button>
</div>
<!-- Loading State -->
<div id="loading" class="loading hidden">
<h3>π Searching for member...</h3>
</div>
<!-- Error Message -->
<div id="error" class="error hidden">
<h4>β Error</h4>
<p id="error-message"></p>
</div>
<!-- Success Message -->
<div id="success" class="success hidden">
<h4>β
Success</h4>
<p id="success-message"></p>
</div>
<!-- User Details -->
<div id="user-section" class="hidden">
<div class="user-card">
<div class="user-info">
<div class="user-details">
<h3 id="user-name">Loading...</h3>
<p><strong>Discord ID:</strong> <span id="user-discord-id"></span></p>
<p><strong>Member Since:</strong> <span id="user-joined"></span></p>
</div>
</div>
<h4>π° Current Balances</h4>
<div id="balance-list" class="balance-list">
<!-- Balances will be populated here -->
</div>
<div class="balance-actions">
<div>
<h4>β Award Points</h4>
<div class="form-group">
<select id="award-currency">
<!-- Options populated dynamically -->
</select>
</div>
<div class="form-group">
<input type="number" id="award-amount" placeholder="Amount to award" min="1">
</div>
<div class="form-group">
<input type="text" id="award-reason" placeholder="Reason (optional)">
</div>
<button class="btn success" onclick="awardPoints()">Award Points</button>
</div>
<div>
<h4>β Deduct Points</h4>
<div class="form-group">
<select id="deduct-currency">
<!-- Options populated dynamically -->
</select>
</div>
<div class="form-group">
<input type="number" id="deduct-amount" placeholder="Amount to deduct" min="1">
</div>
<div class="form-group">
<input type="text" id="deduct-reason" placeholder="Reason (optional)">
</div>
<button class="btn danger" onclick="deductPoints()">Deduct Points</button>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
// π₯ CONFIGURE THESE WITH YOUR ACTUAL VALUES
// β οΈ WARNING: Never expose API keys in client-side code in production!
// This is only safe for local development and learning.
const DRIP_API_KEY = 'your_client_secret_here';
const REALM_ID = 'your_realm_id_here';
const API_BASE = 'https://api.drip.re/api/v1';
let currentUser = null;
let realmCurrencies = [];
// Search for user by Discord ID
async function searchUser() {
const discordId = document.getElementById('discordId').value.trim();
if (!discordId) {
showError('Please enter a Discord ID');
return;
}
showLoading(true);
hideMessages();
hideUserSection();
try {
// Search for member by Discord ID
const response = await fetch(`${API_BASE}/realm/${REALM_ID}/members/search?type=discord&value=${discordId}`, {
headers: {
'Authorization': `Bearer ${DRIP_API_KEY}`,
'Content-Type': 'application/json'
}
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.message || 'Failed to search for member');
}
const data = await response.json();
if (!data.data || data.data.length === 0) {
throw new Error('No member found with that Discord ID');
}
currentUser = data.data[0];
await loadRealmCurrencies();
displayUser(currentUser);
} catch (error) {
console.error('Search error:', error);
showError(error.message);
} finally {
showLoading(false);
}
}
// Load realm currencies for dropdowns
async function loadRealmCurrencies() {
try {
const response = await fetch(`${API_BASE}/realm/${REALM_ID}/points`, {
headers: {
'Authorization': `Bearer ${DRIP_API_KEY}`,
'Content-Type': 'application/json'
}
});
if (!response.ok) {
throw new Error('Failed to load currencies');
}
const data = await response.json();
realmCurrencies = data.data || [];
populateCurrencyDropdowns();
} catch (error) {
console.error('Failed to load currencies:', error);
// Use fallback if available from user balance
if (currentUser && currentUser.pointBalances) {
realmCurrencies = currentUser.pointBalances.map(balance => balance.realmPoint);
populateCurrencyDropdowns();
}
}
}
// Populate currency dropdown options
function populateCurrencyDropdowns() {
const awardSelect = document.getElementById('award-currency');
const deductSelect = document.getElementById('deduct-currency');
// Clear existing options
awardSelect.innerHTML = '';
deductSelect.innerHTML = '';
// Add currency options
realmCurrencies.forEach(currency => {
const option1 = document.createElement('option');
option1.value = currency.id;
option1.textContent = `${currency.emoji || 'π°'} ${currency.name}`;
awardSelect.appendChild(option1);
const option2 = document.createElement('option');
option2.value = currency.id;
option2.textContent = `${currency.emoji || 'π°'} ${currency.name}`;
deductSelect.appendChild(option2);
});
}
// Display user information
function displayUser(user) {
document.getElementById('user-name').textContent = user.displayName || user.username || 'Unknown User';
document.getElementById('user-discord-id').textContent = user.credentials?.find(c => c.type === 'discord')?.platformId || 'N/A';
document.getElementById('user-joined').textContent = user.joinedAt ? new Date(user.joinedAt).toLocaleDateString() : 'Unknown';
// Display balances
const balanceList = document.getElementById('balance-list');
balanceList.innerHTML = '';
if (user.pointBalances && user.pointBalances.length > 0) {
user.pointBalances.forEach(balance => {
const balanceItem = document.createElement('div');
balanceItem.className = 'balance-item';
balanceItem.innerHTML = `
<div class="balance-amount">${balance.balance.toLocaleString()}</div>
<div class="balance-name">${balance.realmPoint.emoji || 'π°'} ${balance.realmPoint.name}</div>
`;
balanceList.appendChild(balanceItem);
});
} else {
balanceList.innerHTML = '<div class="balance-item"><div class="balance-amount">0</div><div class="balance-name">No balances found</div></div>';
}
showUserSection();
}
// Award points to user
async function awardPoints() {
if (!currentUser) return;
const currencyId = document.getElementById('award-currency').value;
const amount = parseInt(document.getElementById('award-amount').value);
const reason = document.getElementById('award-reason').value.trim();
if (!currencyId || !amount || amount <= 0) {
showError('Please select a currency and enter a valid amount');
return;
}
try {
const requestBody = {
tokens: amount
};
if (currencyId) {
requestBody.realmPointId = currencyId;
}
const response = await fetch(`${API_BASE}/realm/${REALM_ID}/members/${currentUser.id}/point-balance`, {
method: 'PATCH',
headers: {
'Authorization': `Bearer ${DRIP_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(requestBody)
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.message || 'Failed to award points');
}
const currency = realmCurrencies.find(c => c.id === currencyId);
const currencyName = currency ? `${currency.emoji || 'π°'} ${currency.name}` : 'points';
showSuccess(`Successfully awarded ${amount} ${currencyName}${reason ? ` for: ${reason}` : ''}!`);
// Clear form
document.getElementById('award-amount').value = '';
document.getElementById('award-reason').value = '';
// Refresh user data
setTimeout(() => {
searchUser();
}, 1000);
} catch (error) {
console.error('Award error:', error);
showError(error.message);
}
}
// Deduct points from user
async function deductPoints() {
if (!currentUser) return;
const currencyId = document.getElementById('deduct-currency').value;
const amount = parseInt(document.getElementById('deduct-amount').value);
const reason = document.getElementById('deduct-reason').value.trim();
if (!currencyId || !amount || amount <= 0) {
showError('Please select a currency and enter a valid amount');
return;
}
try {
const requestBody = {
tokens: -amount // Negative amount for deduction
};
if (currencyId) {
requestBody.realmPointId = currencyId;
}
const response = await fetch(`${API_BASE}/realm/${REALM_ID}/members/${currentUser.id}/point-balance`, {
method: 'PATCH',
headers: {
'Authorization': `Bearer ${DRIP_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(requestBody)
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.message || 'Failed to deduct points');
}
const currency = realmCurrencies.find(c => c.id === currencyId);
const currencyName = currency ? `${currency.emoji || 'π°'} ${currency.name}` : 'points';
showSuccess(`Successfully deducted ${amount} ${currencyName}${reason ? ` for: ${reason}` : ''}!`);
// Clear form
document.getElementById('deduct-amount').value = '';
document.getElementById('deduct-reason').value = '';
// Refresh user data
setTimeout(() => {
searchUser();
}, 1000);
} catch (error) {
console.error('Deduct error:', error);
showError(error.message);
}
}
// UI Helper Functions
function showLoading(show) {
document.getElementById('loading').classList.toggle('hidden', !show);
}
function showError(message) {
document.getElementById('error-message').textContent = message;
document.getElementById('error').classList.remove('hidden');
setTimeout(() => {
document.getElementById('error').classList.add('hidden');
}, 5000);
}
function showSuccess(message) {
document.getElementById('success-message').textContent = message;
document.getElementById('success').classList.remove('hidden');
setTimeout(() => {
document.getElementById('success').classList.add('hidden');
}, 5000);
}
function hideMessages() {
document.getElementById('error').classList.add('hidden');
document.getElementById('success').classList.add('hidden');
}
function showUserSection() {
document.getElementById('user-section').classList.remove('hidden');
}
function hideUserSection() {
document.getElementById('user-section').classList.add('hidden');
}
// Allow Enter key to trigger search
document.getElementById('discordId').addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
searchUser();
}
});
</script>
</body>
</html>
Discord ID Search
/realm/{realmId}/members/search
endpointtype=discord
and the provided Discord IDMulti-Currency Support
/realm/{realmId}/points
Balance Management
/realm/{realmId}/members/{memberId}/point-balance
endpointEnable Developer Mode
Copy User ID
Use in App
Was this page helpful?