Skip to content

Recipes

Each recipe needs a token with the scopes it names, in an EONAUTH_TOKEN environment variable on your server.

Most recipes use this helper (Node 18 or newer).

eonauth.js
const BASE = "https://panel.eonauth.fyi/seller/v1";
export async function eon(method, path, body) {
const res = await fetch(BASE + path, {
method,
headers: {
Authorization: `Bearer ${process.env.EONAUTH_TOKEN}`,
...(body ? { "Content-Type": "application/json" } : {}),
},
body: body ? JSON.stringify(body) : undefined,
});
if (res.status === 429) {
const wait = Number(res.headers.get("Retry-After") ?? 60);
throw Object.assign(new Error(`rate limited, retry in ${wait}s`), { retryAfter: wait });
}
const json = await res.json();
if (!json.ok) throw Object.assign(new Error(`${json.error.code}: ${json.error.message}`), { code: json.error.code });
return json.data;
}
export const APP_ID = "app_ea9745b1df9e4a9bacb22cb1c200993b";

Scope: licenses. Give the key to the buyer in a direct message once your payment provider confirms the order.

import { eon, APP_ID } from "./eonauth.js";
const PRO_TIER = "tier_e26fe8d406f94e13bff9d10c9291c37f";
export async function issueKey(orderId) {
const batch = await eon("POST", "/license/create", {
app_id: APP_ID,
tier_id: PRO_TIER,
preset: "month",
quantity: 1,
note: `discord order ${orderId}`,
});
return batch.licenses[0].key; // shown once: send it now and keep your own record
}

Scopes: licenses, users.

import { eon, APP_ID } from "./eonauth.js";
export async function refund(orderId) {
const { items } = await eon("GET", `/licenses?app_id=${APP_ID}&q=${encodeURIComponent(`order ${orderId}`)}`);
for (const key of items) {
await eon("POST", "/license/revoke", { license_id: key.id, reason: `refund ${orderId}` });
if (key.user_id) await eon("POST", "/user/ban", { user_id: key.user_id, reason: `refund ${orderId}` });
}
}

Revoking takes away the time the key gave. Banning also ends the user’s other sessions, whatever keys they hold.

Scope: users. For a “I got a new PC” request.

import { eon, APP_ID } from "./eonauth.js";
export async function resetPc(username) {
const { items } = await eon("GET", `/users?app_id=${APP_ID}&q=${encodeURIComponent(username)}`);
const user = items.find((u) => u.username === username);
if (!user) return "No such user.";
try {
const r = await eon("POST", "/user/reset-hwid", { user_id: user.id });
return r.reset ? `Done. ${r.hwid_resets_used} of ${r.allowance} resets used.` : r.reason;
} catch (err) {
if (err.code === "HWID_RESET_QUOTA_EXCEEDED") return "No resets left. Ask the owner.";
if (err.code === "HWID_RESET_COOLDOWN") return "Reset too recently. Try again later.";
throw err;
}
}

Scope: users. Give everyone a day back.

Terminal window
curl -X POST https://panel.eonauth.fyi/seller/v1/users/time \
-H "Authorization: Bearer $EONAUTH_TOKEN" \
-H "Content-Type: application/json" \
-d '{"app_id":"app_ea9745b1df9e4a9bacb22cb1c200993b","all_users":true,"seconds":86400,"reason":"outage 12 Nov"}'

Scopes: licenses, users. Exports hold up to 5,000 rows each and never contain whole keys.

import json, os, datetime, requests
BASE = "https://panel.eonauth.fyi/seller/v1"
APP_ID = "app_ea9745b1df9e4a9bacb22cb1c200993b"
H = {"Authorization": f"Bearer {os.environ['EONAUTH_TOKEN']}"}
day = datetime.date.today().isoformat()
for name in ("licenses", "users"):
r = requests.get(f"{BASE}/{name}/export", params={"app_id": APP_ID}, headers=H, timeout=60)
data = r.json()["data"]
if data["truncated"]:
print(f"warning: {name} export hit 5,000 rows")
with open(f"backup-{name}-{day}.json", "w") as f:
json.dump(data["items"], f)

Scope: variables. Your app reads the variable by ID, so changing it reaches users the next time the app fetches it.

import { eon } from "./eonauth.js";
await eon("POST", "/variable/update", {
variable_id: "var_342c8c7e97e24ae1b79183b18d7011d5",
value: "https://cdn.example.com/pro/build-1.5.0.zip",
});