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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file artifacts_mmo-0.1.1.tar.gz.
File metadata
- Download URL: artifacts_mmo-0.1.1.tar.gz
- Upload date:
- Size: 25.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d08b3aa7cdc2d5df41dd51b519eee2a7b6af010bc1c88e9963f3544ceb98ed78
|
|
| MD5 |
e7fa6c4b4b7679971c42b46d3cf407f4
|
|
| BLAKE2b-256 |
a3cb9cc95a5d9f755369118e8ad28587ec198c6d836f1911354d249fe6339bcb
|
File details
Details for the file artifacts_mmo-0.1.1-py3-none-any.whl.
File metadata
- Download URL: artifacts_mmo-0.1.1-py3-none-any.whl
- Upload date:
- Size: 41.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bc853dd294484397c3292ba4061ecbb651782dc93c1ec2ec24e137c2447ea0b3
|
|
| MD5 |
50aee49380af8543deae39e06366e504
|
|
| BLAKE2b-256 |
418beb20d98219015d93e2839aa519a81363f2b57f26c6ed3e4b8a1fe762c93f
|