Skip to content

Instantly share code, notes, and snippets.

@cptmacp
Last active February 5, 2026 19:22
Show Gist options
  • Select an option

  • Save cptmacp/1e9a9f20f69c113a0828fea8d13cb34c to your computer and use it in GitHub Desktop.

Select an option

Save cptmacp/1e9a9f20f69c113a0828fea8d13cb34c to your computer and use it in GitHub Desktop.
automate for skport endfield daily login claim via js script and send notification to discord channel
/** Config Starts. **/
const profiles = [
{
cred: "xxxxxxxxxxxxxxxxxxxxxx", // Replace with your Endfield cred cookie value ( get from cookie )
skGameRole: "xxxxxxxxxxxx", // Replace with your Endfield skGameRole cookie value ( get from cookie )
platform: "3",
vName: "1.0.0",
accountName: "acc_name" // Replace with a name to identify this account( a simple identifier )
}
// Add more profiles if needed
];
const discord_notify = true;
const myDiscordID = "xxxxxxxxxxxxxxxxxxx"; // Replace with your Discord ID (optional, for pinging)
const discordWebhook = "https://xxxx.discord.com/api/webhooks/xxxxxxxxxxx"; // Replace with your Discord webhook URL
/** Config ends. **/
const attendanceUrl = 'https://zonai.skport.com/web/v1/game/endfield/attendance';
async function main() {
const results = await Promise.all(profiles.map(autoClaimFunction));
if (discord_notify && discordWebhook) {
postWebhook(results);
}
}
function autoClaimFunction({ cred, skGameRole, platform, vName, accountName }) {
console.log(`[${accountName}] Checking credentials and performing check-in...`);
const timestamp = Math.floor(Date.now() / 1000).toString();
// Attempt to refresh token used for signing. If refresh fails, token will be empty.
let token = "";
try {
token = refreshToken(cred, platform, vName);
console.log(`[${accountName}] Token refreshed successfully.`);
} catch (e) {
console.error(`[${accountName}] Token refresh failed: ${e.message}`);
// proceed with empty token; API may reject if token required
}
const sign = generateSign('/web/v1/game/endfield/attendance', '', timestamp, token, platform, vName);
const header = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:147.0) Gecko/20100101 Firefox/147.0',
'Accept': '*/*',
'Accept-Language': 'en-US,en;q=0.9',
'Accept-Encoding': 'gzip, deflate, br, zstd',
'Referer': 'https://game.skport.com/',
'Content-Type': 'application/json',
'sk-language': 'en',
'sk-game-role': skGameRole,
'cred': cred,
'platform': platform,
'vName': vName,
'timestamp': timestamp,
'sign': sign,
'Origin': 'https://game.skport.com',
'Connection': 'keep-alive',
'Sec-Fetch-Dest': 'empty',
'Sec-Fetch-Mode': 'cors',
'Sec-Fetch-Site': 'same-site'
};
const options = {
method: 'POST',
headers: header,
muteHttpExceptions: true,
};
let result = {
name: accountName,
success: false,
status: "",
rewards: ""
};
try {
const endfieldResponse = UrlFetchApp.fetch(attendanceUrl, options);
const responseJson = JSON.parse(endfieldResponse.getContentText());
console.log(`[${accountName}] API Response Code: ${responseJson.code}`);
if (responseJson.code === 0) {
result.success = true;
result.status = "✅ Check-in Successful";
if (responseJson.data && responseJson.data.awardIds) {
const awards = responseJson.data.awardIds.map(award => {
const resource = responseJson.data.resourceInfoMap ? responseJson.data.resourceInfoMap[award.id] : null;
return resource ? `${resource.name} x${resource.count}` : (award.id || "Unknown Item");
}).join('\n');
result.rewards = awards;
} else {
result.rewards = "No detailed reward info.";
}
} else if (responseJson.code === 10001) {
result.success = true;
result.status = "👌 Already Checked In";
result.rewards = "Nothing to claim";
} else {
result.success = false;
result.status = `❌ Error (Code: ${responseJson.code})`;
result.rewards = responseJson.message || "Unknown Error";
}
} catch (error) {
result.success = false;
result.status = "💥 Exception";
result.rewards = error.message;
console.error(`[${accountName}] Exception: ${error.message}`);
}
return result;
}
function postWebhook(results) {
console.log('Posting to Discord webhook...');
const allSuccess = results.every(r => r.success);
const hasError = !allSuccess;
const embedColor = allSuccess ? 5763719 : 15548997; // Green or Red
const fields = results.map(r => {
return {
name: `👤 ${r.name}`,
value: `**Status:** ${r.status}\n**Rewards:**\n${r.rewards ? r.rewards : 'None'}`,
inline: true
};
});
const payload = {
username: "Endfield Assistant",
avatar_url: "https://pbs.twimg.com/profile_images/1984225639407529984/2_3-HRTS_400x400.jpg",
embeds: [{
title: "📡 Endfield Daily Check-in Report",
color: embedColor,
fields: fields,
footer: {
text: `Time: ${new Date().toLocaleString('en-US', { timeZone: 'UTC' })} (UTC)`,
icon_url: "https://assets.skport.com/assets/favicon.ico"
}
}]
};
if (hasError && myDiscordID) {
payload.content = `<@${myDiscordID}> Script encountered an error, please check logs!`;
}
const options = {
method: 'POST',
contentType: 'application/json',
payload: JSON.stringify(payload),
muteHttpExceptions: true
};
try {
UrlFetchApp.fetch(discordWebhook, options);
} catch (e) {
console.error("Failed to send Discord webhook: " + e.message);
}
}
/** Helper: Refresh token used for signing **/
function refreshToken(cred, platform, vName) {
const refreshUrl = 'https://zonai.skport.com/web/v1/auth/refresh';
const header = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Accept': 'application/json, text/plain, */*',
'cred': cred,
'platform': platform,
'vName': vName,
'Origin': 'https://game.skport.com',
'Referer': 'https://game.skport.com/'
};
const options = {
method: 'GET',
headers: header,
muteHttpExceptions: true
};
const response = UrlFetchApp.fetch(refreshUrl, options);
const json = JSON.parse(response.getContentText());
if (json.code === 0 && json.data && json.data.token) {
return json.data.token;
} else {
throw new Error(`Refresh Failed (Code: ${json.code}, Msg: ${json.message})`);
}
}
/** Signature generation (HMAC-SHA256 then MD5) **/
function generateSign(path, body, timestamp, token, platform, vName) {
let str = path + body + timestamp;
const headerJson = `{"platform":"${platform}","timestamp":"${timestamp}","dId":"","vName":"${vName}"}`;
str += headerJson;
const hmacBytes = Utilities.computeHmacSha256Signature(str, token || '');
const hmacHex = bytesToHex(hmacBytes);
const md5Bytes = Utilities.computeDigest(Utilities.DigestAlgorithm.MD5, hmacHex);
return bytesToHex(md5Bytes);
}
function bytesToHex(bytes) {
return bytes.map(function(byte) {
return ('0' + (byte & 0xFF).toString(16)).slice(-2);
}).join('');
}
@Ciberr2
Copy link

Ciberr2 commented Feb 4, 2026

did you enable, "Allow userscript"

After installing just open the link "https://game.skport.com/endfield/sign-in?header=0&hg_media=skport&hg_link_campaign=tools"

and you should see the popup on top right side

Seems like it fixed itself after reinstalling the script.

@cptmacp
Copy link
Author

cptmacp commented Feb 4, 2026

@cptmacp thanks for the script. <3 Do you happen to know what to change so the name in the discord message would be a user ping? Before I could just change the variable of username to "<@" + myDiscordID + ">. But I cant figure it out where/how to change it in the updated version. :) As it just gets out as plain text instead of the ping in Discord.

image But it should be like this,, if possible. :D image

Hey, the ping will only happen in case of

https://gist.github.com/cptmacp/1e9a9f20f69c113a0828fea8d13cb34c#file-endfield_discord-js-L149

hasError is populated, it wont ping in normal scenario.

image

@itreecoke-del
Copy link

@cptmacp thanks for the script. <3 Do you happen to know what to change so the name in the discord message would be a user ping? Before I could just change the variable of username to "<@" + myDiscordID + ">. But I cant figure it out where/how to change it in the updated version. :) As it just gets out as plain text instead of the ping in Discord.

I can send what I looked up to change the message back to the old written text instead of the new layout since I preferred the old one.
1000019687

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment