Skip to main content

Async Python wrapper for the Artifacts MMO API

Project description

Artifacts MMO - Python Wrapper

Async Python wrapper for the Artifacts MMO API. Control up to 5 characters simultaneously with full type safety and IDE autocompletion.

  • 65 endpoints covered (every single one)
  • Async built on aiohttp -- run multiple characters in parallel
  • Typed with Pydantic v2 models -- full IDE autocompletion
  • Simple -- character-centric design, beginner friendly

Installation

pip install -e .

Requirements: Python 3.10+

Quick Start

import asyncio
from artifacts import ArtifactsClient, wait_for_cooldown

async def main():
    async with ArtifactsClient(token="your_token_here") as client:
        # Get a character controller
        char = client.character("MyCharacter")

        # Fetch character info
        info = await char.get()
        print(f"{info.name} lv{info.level} HP={info.hp}/{info.max_hp}")

        # Fight a monster
        result = await char.fight()
        print(f"Result: {result.fight.result.value}")

        # Wait for cooldown before next action
        await wait_for_cooldown(result.cooldown)

asyncio.run(main())

Getting a Token

You need a JWT token to authenticate. Generate one from your account credentials:

async with ArtifactsClient() as client:
    token = await client.token.generate("your_username", "your_password")
    print(token)  # Use this token from now on

Or use a token you already have from the Artifacts website.

Custom API URL

By default the wrapper connects to https://api.artifactsmmo.com/. To use a different server (e.g. sandbox):

client = ArtifactsClient(
    token="your_token",
    base_url="https://api.sandbox.artifactsmmo.com",
)

Architecture Overview

ArtifactsClient
├── .character("name")     -> Character (34 action methods)
├── .server                -> ServerAPI
├── .token                 -> TokenAPI
├── .accounts              -> AccountsAPI
├── .my_account            -> MyAccountAPI
├── .characters            -> CharactersAPI
├── .items                 -> ItemsAPI
├── .monsters              -> MonstersAPI
├── .maps                  -> MapsAPI
├── .resources             -> ResourcesAPI
├── .npcs                  -> NPCsAPI
├── .events                -> EventsAPI
├── .achievements          -> AchievementsAPI
├── .badges                -> BadgesAPI
├── .effects               -> EffectsAPI
├── .grand_exchange        -> GrandExchangeAPI
├── .leaderboard           -> LeaderboardAPI
├── .tasks                 -> TasksAPI
├── .simulation            -> SimulationAPI
└── .sandbox               -> SandboxAPI

Fetching Game Data

All game data endpoints are read-only and return typed Pydantic models. Paginated results come wrapped in DataPage[T].

Items

# Get a single item by code
item = await client.items.get("copper_ore")
print(f"{item.name} (lv{item.level}, type={item.type.value})")

# List items with filters
page = await client.items.get_all(min_level=1, max_level=10, type="resource", size=20)
for item in page.data:
    print(f"  {item.code}: {item.name}")
print(f"Page {page.page}/{page.pages} (total: {page.total})")

Monsters

monster = await client.monsters.get("chicken")
print(f"{monster.name} lv{monster.level} HP={monster.hp}")
print(f"Drops: {[(d.code, d.rate) for d in monster.drops]}")

# List all monsters in a level range
page = await client.monsters.get_all(min_level=1, max_level=5)

Maps

# Find maps containing a specific monster
maps = await client.maps.get_all(content_type="monster", content_code="chicken")
for m in maps.data:
    print(f"  ({m.x},{m.y}) layer={m.layer.value}")

# Get a specific map tile
tile = await client.maps.get_by_position("overworld", 0, 1)

# Get a map by its ID
tile = await client.maps.get_by_id(42)

Resources

# All mining resources
page = await client.resources.get_all(skill="mining", min_level=1)
for r in page.data:
    print(f"  {r.code} (lv{r.level}) drops: {[d.code for d in r.drops]}")

NPCs

# List all NPCs
npcs = await client.npcs.get_all()

# Get items sold by an NPC
items = await client.npcs.get_items("merchant_1")
for i in items.data:
    print(f"  {i.code} buy={i.buy_price} sell={i.sell_price}")

Other game data

# Achievements
all_achievements = await client.achievements.get_all()
single = await client.achievements.get("first_kill")

# Badges
badges = await client.badges.get_all()

# Effects
effects = await client.effects.get_all()

# Events
active = await client.events.get_all_active()
all_events = await client.events.get_all()

# Tasks
tasks = await client.tasks.get_all(type="monsters", min_level=1)
rewards = await client.tasks.get_all_rewards()

# Leaderboard
top_chars = await client.leaderboard.get_characters(sort="combat")
top_accounts = await client.leaderboard.get_accounts(sort="gold")

# Grand Exchange
orders = await client.grand_exchange.get_orders(code="copper_ore")
history = await client.grand_exchange.get_history("copper_ore")

Pagination

All list endpoints return a DataPage[T]:

page = await client.items.get_all(page=1, size=50)
page.data    # list[ItemSchema] -- the items on this page
page.total   # int -- total number of items across all pages
page.page    # int -- current page number
page.pages   # int -- total number of pages
page.size    # int -- page size

To fetch every item across all pages at once, use the HTTP client helper:

all_items = await client._http.get_all_pages("/items", ItemSchema, page_size=100)
# Returns a flat list[ItemSchema] with every item

Account & Bank

# Account details
account = await client.my_account.get_details()
print(f"{account.username} -- gems={account.gems}")

# Bank info
bank = await client.my_account.get_bank()
print(f"Gold: {bank.gold}, Slots: {bank.slots}/{bank.slots}")

# Bank items
bank_items = await client.my_account.get_bank_items()
for item in bank_items.data:
    print(f"  {item.code} x{item.quantity}")

# Your characters
chars = await client.my_account.get_characters()

# Your GE orders and history
orders = await client.my_account.get_ge_orders()
history = await client.my_account.get_ge_history()

# Pending items (from achievements, events, etc.)
pending = await client.my_account.get_pending_items()

Character Actions

Create a character controller, then call action methods. Every action returns a result containing a cooldown field.

char = client.character("MyCharacter")

Movement

# Move by coordinates
result = await char.move(x=2, y=3)
await wait_for_cooldown(result.cooldown)

# Move by map ID
result = await char.move(map_id=42)
await wait_for_cooldown(result.cooldown)

# Layer transition (e.g. enter a building)
result = await char.transition()
await wait_for_cooldown(result.cooldown)

Combat

# Solo fight
result = await char.fight()
fight = result.fight
print(f"{fight.result.value} in {fight.turns} turns")
for cr in fight.characters:
    print(f"  +{cr.xp}xp +{cr.gold}g, drops={[d.code for d in cr.drops]}")
await wait_for_cooldown(result.cooldown)

# Boss fight with other characters (up to 3 total)
result = await char.fight(participants=["Char2", "Char3"])

# Rest to recover HP
result = await char.rest()
print(f"Restored {result.hp_restored} HP")
await wait_for_cooldown(result.cooldown)

Equipment

from artifacts.models import ItemSlot

# Equip
result = await char.equip(code="iron_sword", slot=ItemSlot.WEAPON)
await wait_for_cooldown(result.cooldown)

# Unequip
result = await char.unequip(slot=ItemSlot.WEAPON)
await wait_for_cooldown(result.cooldown)

Gathering & Crafting

# Gather (character must be on a resource tile)
result = await char.gathering()
print(f"+{result.details.xp}xp, got: {[d.code for d in result.details.items]}")
await wait_for_cooldown(result.cooldown)

# Craft (character must be at a workshop)
result = await char.crafting(code="iron_sword", quantity=1)
await wait_for_cooldown(result.cooldown)

# Recycle equipment
result = await char.recycling(code="iron_sword", quantity=1)
await wait_for_cooldown(result.cooldown)

Bank Operations

# Character must be on a bank tile

# Gold
result = await char.bank_deposit_gold(quantity=500)
result = await char.bank_withdraw_gold(quantity=200)

# Items
from artifacts.models import SimpleItemSchema
items = [SimpleItemSchema(code="copper_ore", quantity=50)]
result = await char.bank_deposit_items(items)
result = await char.bank_withdraw_items(items)

# Buy a bank expansion (+20 slots)
result = await char.bank_buy_expansion()

NPC Trading

# Character must be on an NPC tile
result = await char.npc_buy(code="wooden_staff", quantity=1)
result = await char.npc_sell(code="wooden_staff", quantity=1)

Grand Exchange

# Character must be on a GE tile

# Buy from an existing sell order
result = await char.ge_buy(id="order_id_here", quantity=10)

# Create a sell order
result = await char.ge_create_sell_order(code="copper_ore", quantity=100, price=5)

# Create a buy order (gold is locked upfront)
result = await char.ge_create_buy_order(code="copper_ore", quantity=100, price=5)

# Fill someone's buy order by selling to it
result = await char.ge_fill(id="order_id_here", quantity=50)

# Cancel your order
result = await char.ge_cancel_order(id="order_id_here")

Tasks

# Accept a new task (character must be at a tasks master)
result = await char.task_new()
print(f"Task: {result.task.code} ({result.task.type.value}) x{result.task.total}")

# Trade items for the task
result = await char.task_trade(code="copper_ore", quantity=10)

# Complete the task
result = await char.task_complete()

# Exchange 6 task coins for a random reward
result = await char.task_exchange()

# Cancel current task (costs 1 task coin)
result = await char.task_cancel()

Consumables & Items

# Use a consumable
result = await char.use(code="healing_potion", quantity=1)

# Delete an item from inventory
result = await char.delete_item(code="junk_item", quantity=5)

Give Items/Gold to Another Character

# Characters must be on the same map tile

# Give gold
result = await char.give_gold(quantity=100, character="OtherChar")

# Give items
items = [SimpleItemSchema(code="copper_ore", quantity=20)]
result = await char.give_items(items=items, character="OtherChar")

Other

# Claim a pending item
result = await char.claim_item(id=123)

# Change character skin
from artifacts.models import CharacterSkin
result = await char.change_skin(skin=CharacterSkin.MEN2)

# View action logs
logs = await char.get_logs(page=1, size=20)
for log in logs.data:
    print(f"  [{log.type.value}] {log.description}")

Cooldown Handling

Every action returns a cooldown object. The wrapper never waits automatically -- you decide when to wait.

from artifacts import wait_for_cooldown, cooldown_seconds

result = await char.fight()

# Option 1: Helper that sleeps for the remaining duration
await wait_for_cooldown(result.cooldown)

# Option 2: Read the value and handle it yourself
seconds = cooldown_seconds(result.cooldown)
print(f"Cooldown: {seconds}s remaining")
await asyncio.sleep(seconds)

# Option 3: Access the raw CooldownSchema
cd = result.cooldown
print(f"Total: {cd.total_seconds}s")
print(f"Remaining: {cd.remaining_seconds}s")
print(f"Reason: {cd.reason.value}")
print(f"Expires at: {cd.expiration}")

Error Handling

The wrapper raises typed exceptions mapped to API error codes:

from artifacts.errors import (
    ArtifactsAPIError,       # Base class for all API errors
    CooldownActiveError,     # 499 -- character is in cooldown
    ActionInProgressError,   # 486 -- action already running
    InventoryFullError,      # 497 -- inventory full
    InsufficientGoldError,   # 492 -- not enough gold
    NotFoundError,           # 404 -- resource not found
    ContentNotOnMapError,    # 598 -- no monster/resource here
    AlreadyAtDestinationError, # 490 -- already at target
    SkillLevelTooLowError,   # 493 -- skill level too low
    EquipmentSlotError,      # 491 -- equipment slot issue
    MapBlockedError,         # 596 -- map is blocked
    NoPathError,             # 595 -- no path to destination
    MemberRequiredError,     # 451 -- member/founder required
    ConditionsNotMetError,   # 496 -- conditions not met
    TaskError,               # 474-489 -- task-related errors
    GrandExchangeError,      # 433-438 -- GE errors
    ValidationError,         # 422 -- invalid request
)

Example:

try:
    result = await char.fight()
    await wait_for_cooldown(result.cooldown)
except CooldownActiveError:
    await asyncio.sleep(3)
except InventoryFullError:
    print("Inventory full! Go deposit at the bank.")
except ContentNotOnMapError:
    print("No monster on this tile.")
except ArtifactsAPIError as e:
    print(f"API error [{e.code}]: {e.message}")

Running Multiple Characters in Parallel

Use asyncio.gather() to run multiple characters at the same time:

import asyncio
from artifacts import ArtifactsClient, wait_for_cooldown

async def combat_loop(char):
    for _ in range(10):
        info = await char.get()
        if info.hp < info.max_hp * 0.3:
            result = await char.rest()
            await wait_for_cooldown(result.cooldown)
            continue
        result = await char.fight()
        print(f"[{char.name}] {result.fight.result.value}")
        await wait_for_cooldown(result.cooldown)

async def main():
    async with ArtifactsClient(token="your_token") as client:
        names = ["Char1", "Char2", "Char3", "Char4", "Char5"]
        chars = [client.character(n) for n in names]
        await asyncio.gather(*[combat_loop(c) for c in chars])

asyncio.run(main())

See examples/combat_loop_5chars.py for a complete example with error handling, movement, and drop tracking.


Character Management

from artifacts.models import CharacterSkin

# Create a character (max 5 per account)
new_char = await client.characters.create("NewHero", CharacterSkin.MEN1)

# Delete a character
deleted = await client.characters.delete("NewHero")

# List all active characters on the server
active = await client.characters.get_active()

# Get any character's public info
info = await client.characters.get("SomePlayer")

Simulation (Members Only)

from artifacts.models import FakeCharacterSchema

fake = FakeCharacterSchema(
    level=20,
    weapon_slot="iron_sword",
    body_armor_slot="iron_armor",
)
result = await client.simulation.fight(
    characters=[fake],
    monster="ogre",
    iterations=100,
)
print(f"Winrate: {result.winrate:.1%} ({result.wins}W / {result.losses}L)")

Sandbox (Sandbox Server Only)

When using the sandbox server (base_url="https://api.sandbox.artifactsmmo.com"):

await client.sandbox.give_gold("MyChar", 10000)
await client.sandbox.give_item("MyChar", "iron_sword", 5)
await client.sandbox.give_xp("MyChar", "combat", 5000)
await client.sandbox.spawn_event("event_code")
await client.sandbox.reset_account()

Complete API Reference

Client Sub-Accessors

Accessor Methods
client.server get_status()
client.token generate(username, password)
client.accounts create(), forgot_password(), reset_password(), get(), get_achievements(), get_characters()
client.my_account get_details(), get_bank(), get_bank_items(), get_ge_orders(), get_ge_history(), get_pending_items(), change_password(), get_characters(), get_all_logs()
client.characters create(), delete(), get_active(), get()
client.items get_all(), get()
client.monsters get_all(), get()
client.maps get_all(), get_layer(), get_by_position(), get_by_id()
client.resources get_all(), get()
client.npcs get_all(), get(), get_all_items(), get_items()
client.events get_all_active(), get_all(), spawn()
client.achievements get_all(), get()
client.badges get_all(), get()
client.effects get_all(), get()
client.grand_exchange get_history(), get_orders(), get_order()
client.leaderboard get_characters(), get_accounts()
client.tasks get_all(), get(), get_all_rewards(), get_reward()
client.simulation fight()
client.sandbox give_gold(), give_item(), give_xp(), spawn_event(), reset_account()

Character Methods

Category Methods
Info get(), get_logs()
Movement move(x, y), move(map_id), transition()
Combat fight(), rest()
Equipment equip(code, slot), unequip(slot)
Skills gathering(), crafting(code, qty), recycling(code, qty)
Items use(code, qty), delete_item(code, qty)
Bank bank_deposit_gold(qty), bank_withdraw_gold(qty), bank_deposit_items(items), bank_withdraw_items(items), bank_buy_expansion()
NPC npc_buy(code, qty), npc_sell(code, qty)
Grand Exchange ge_buy(id, qty), ge_create_sell_order(code, qty, price), ge_create_buy_order(code, qty, price), ge_cancel_order(id), ge_fill(id, qty)
Tasks task_new(), task_complete(), task_exchange(), task_trade(code, qty), task_cancel()
Give give_gold(qty, character), give_items(items, character)
Misc claim_item(id), change_skin(skin)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

artifacts_mmo-0.1.3.tar.gz (27.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

artifacts_mmo-0.1.3-py3-none-any.whl (42.4 kB view details)

Uploaded Python 3

File details

Details for the file artifacts_mmo-0.1.3.tar.gz.

File metadata

  • Download URL: artifacts_mmo-0.1.3.tar.gz
  • Upload date:
  • Size: 27.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.4

File hashes

Hashes for artifacts_mmo-0.1.3.tar.gz
Algorithm Hash digest
SHA256 3c5f4bfc91f7e940dced329fa0907b57049466b52e006cf5dc041af3b099609f
MD5 7543706f90f80eafac8cf8e99c37fcdd
BLAKE2b-256 f939be0ec34f09ad5dd926635609cb931d05e1c78b8def51e90e89dfec71e9da

See more details on using hashes here.

File details

Details for the file artifacts_mmo-0.1.3-py3-none-any.whl.

File metadata

  • Download URL: artifacts_mmo-0.1.3-py3-none-any.whl
  • Upload date:
  • Size: 42.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.4

File hashes

Hashes for artifacts_mmo-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 ddded7d38ec7ce3d3745445e1cd43f267e474b26bd07f7785474719e70e26f59
MD5 27a3e5d4f25d0da68bb3872851bffdcd
BLAKE2b-256 34b384364fedb6ab3366d6979c6a95acbd3b4c0a15f220914266ba6f27c4f6b7

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page