Developers
Products
Quickstart

Use the API

Recipes

Copyable examples: a profile card on your website, a Discord bot command, and AlloyMC profiles for players on your Minecraft server.

Updated · Markdown

A profile card on your site

Plain HTML and JavaScript, no build step. Put it anywhere on a page:

<div class="alloy-card" data-handle="elchi"></div>
<script type="module">
  for (const el of document.querySelectorAll(".alloy-card")) {
    const res = await fetch(`https://api.alloymc.dev/v1/users/${el.dataset.handle}`);
    if (!res.ok) continue;
    const u = await res.json();
    const img = Object.assign(document.createElement("img"), {
      src: u.avatarUrl.replace("avatar.png?", "avatar.png?s=128&"),
      width: 64, height: 64, alt: "",
    });
    img.style.imageRendering = "pixelated";
    const link = Object.assign(document.createElement("a"), {
      href: u.profileUrl,
      textContent: u.displayName,
    });
    const meta = document.createElement("small");
    meta.textContent = u.private ? "Private profile" : `${u.followers} followers`;
    el.append(img, link, meta);
  }
</script>

Building the card with textContent instead of innerHTML keeps someone's display name from being read as HTML.

A Discord bot command

With discord.js 14, a /alloy handle:<name> command that answers with an embed:

import { Client, EmbedBuilder, Events, GatewayIntentBits } from "discord.js";

const client = new Client({ intents: [GatewayIntentBits.Guilds] });

client.on(Events.InteractionCreate, async (i) => {
  if (!i.isChatInputCommand() || i.commandName !== "alloy") return;
  const handle = i.options.getString("handle", true);
  const res = await fetch(`https://api.alloymc.dev/v1/users/${encodeURIComponent(handle)}`);
  if (!res.ok) return i.reply({ content: "No one on AlloyMC has that handle.", ephemeral: true });
  const u = await res.json();
  const embed = new EmbedBuilder()
    .setTitle(u.displayName)
    .setURL(u.profileUrl)
    .setThumbnail(u.avatarUrl.replace("avatar.png?", "avatar.png?s=256&"))
    .setDescription(u.bio || null)
    .addFields(
      { name: "Followers", value: String(u.followers ?? "Private"), inline: true },
      { name: "Minecraft", value: u.minecraft?.map((m) => m.name).join(", ") || "None shown", inline: true },
    );
  await i.reply({ embeds: [embed] });
});

client.login(process.env.DISCORD_TOKEN);

Register the command with a required string option called handle, as described in the discord.js guide.

AlloyMC profiles for players on your server

Show which of your players have an AlloyMC profile, for example on your server's website. Look each player up by UUID and cache the answer:

import time
import requests

cache = {}  # uuid -> (time, profile or None)

def alloymc_profile(uuid: str):
    hit = cache.get(uuid)
    if hit and time.time() - hit[0] < 600:
        return hit[1]
    r = requests.get(f"https://api.alloymc.dev/v1/minecraft/{uuid}", timeout=10)
    profile = r.json()["user"] if r.status_code == 200 else None
    cache[uuid] = (time.time(), profile)
    return profile

for uuid in ["069a79f444e94726a5befca90e38aaf5"]:
    p = alloymc_profile(uuid)
    print(uuid, "->", p["profileUrl"] if p else "no public AlloyMC profile")

404 simply means the player hasn't linked a public profile, which is the common case. Keep lookups under the rate limit by caching like this.

Check for a new Alloy version

curl -s https://api.alloymc.dev/v1/launcher/releases/latest

The answer has version, published, release notes in Markdown, and the signed update files per platform with their SHA-256.