Skip to main content

API Reference

REST API for the AT1AS v2 server (Rust / Axum / Postgres). All responses are JSON.

  • Base URL (dev): http://127.0.0.1:8080 (use 127.0.0.1, not localhost)
  • Auth: session-token bearer header on protected routes: Authorization: Bearer <token> (obtained from register/login)
  • Bodies: Content-Type: application/json
  • :id params marked (id|code) accept either a numeric id or a text code (e.g. /api/station/terra or /api/station/1).

Error formatโ€‹

Every handler error returns:

{ "error": { "code": "...", "message": "..." } }
codeHTTPmeaning
bad_request400invalid input / rule violation
unauthorized401missing/invalid token or bad credentials
not_found404resource (or owned ship) doesn't exist
conflict409uniqueness clash (email/username)
internal500unexpected server/DB error

Note: an unmatched path currently returns a bare 404 with empty body (no global JSON fallback yet).

Legendโ€‹

๐Ÿ”“ public ยท ๐Ÿ”‘ requires auth ยท ๐Ÿ‘ค requires auth and ownership of the ship ยท โš“ ship must be docked ยท ๐Ÿญ station must offer the noted service


Auth & accountโ€‹

POST /api/user/register ๐Ÿ”“โ€‹

Create an account. Bootstraps a full starting state in one transaction: user + player character + wallet (50,000 โ‚ก) + a starter shuttle docked at Terra + 3 NPC crew (pilot/engineer/gunner).

// body
{ "email": "pilot@at1as.test", "password": "min8chars" }
// 200
{ "token","user_id","expires_at","character_id","credits":50000,
"ship": { "ship_id","name","hull","hp","station" },
"crew": [ { "character_id","name","role" } ] }

409 if the email is already registered.

POST /api/user/login ๐Ÿ”“โ€‹

{ "email","password" } // body
{ "token","user_id","expires_at" } // 200 ยท 401 on bad credentials

POST /api/user/logout ๐Ÿ”‘โ€‹

Deletes the presented session token. โ†’ { "ok": true, "ended": <n> }

POST /api/user/forgot ๐Ÿ”“โ€‹

{ "email" } โ†’ { "ok": true, "reset_token"? } (token returned only in dev; never reveals whether the account exists).

GET /api/user/oauth?provider=google ๐Ÿ”“โ€‹

Stub. Returns { provider, configured:false, status:"not_configured", authorize_url, redirect_uri }.

GET /api/user/me ๐Ÿ”‘โ€‹

The account: user + each character with wallet + ship count.

{ "user": { "id","email","username","status","created_at","last_login_at" },
"characters": [ { "character_id","name","kind","archetype",
"wallet": { "credits","tokens" }, "ship_count" } ] }

POST /api/user/username ๐Ÿ”‘โ€‹

{ "username" } (3โ€“32 chars) โ†’ { "ok":true, "username" } ยท 409 if taken.

POST /api/user/password ๐Ÿ”‘โ€‹

{ "current_password","new_password" } (new โ‰ฅ 8). Verifies the current password, then revokes all sessions. โ†’ { "ok":true, "sessions_revoked":true } ยท 401 if the current password is wrong.

GET /api/wallet ๐Ÿ”‘โ€‹

โ†’ { "character_id","credits","tokens" }

GET /api/standing ๐Ÿ”‘โ€‹

Faction reputation (signed; 0 = neutral). โ†’ { "standing": [ { "faction","name","value" } ] }

GET /api/transactions ๐Ÿ”‘โ€‹

The caller's ledger, most-recent first (capped 100). Each row: { id, ts, kind, item, qty, unit_price, credits_amount, station_id, role } (role = buyer/seller/party).


Shipsโ€‹

GET /api/ship/list ๐Ÿ”‘โ€‹

Every ship owned by the caller. โ†’ { "count", "ships": [ <ship object> ] }

GET /api/ship/:id ๐Ÿ”“โ€‹

Full ship object (see Ship object). 404 if missing.

POST /api/ship/buy ๐Ÿ”‘ โš“๐Ÿญshipyardโ€‹

Buy a hull from a colony's shipyard stock; the new ship docks at that colony.

{ "colony":"pallas", "hull":"gunship" } // body
{ "ship_id","hull","name","station","credits_spent","wallet_credits" }

400 if the colony has no shipyard service, no stock, or you can't afford it.

POST /api/ship/:id/rename ๐Ÿ‘คโ€‹

{ "name" } (โ‰ค48) โ†’ { "ship_id","name" }

POST /api/ship/:id/dock ๐Ÿ‘คโ€‹

{ "station": "(id|code)" } โ†’ { "ship_id","status":"docked","station":{id,code,name} }

POST /api/ship/:id/undock ๐Ÿ‘คโ€‹

โ†’ { "ship_id","status":"flying" }

POST /api/ship/:id/refuel ๐Ÿ‘ค โš“๐Ÿญrefuelโ€‹

Buy reaction mass / fusion fuel into the ship's tanks. Priced per-kg from item_types.base_price รท mass_kg_per_unit.

{ "remass_kg"?: 2000, "fusion_kg"?: 0 }
{ "ship_id","remass_kg","fusion_kg","credits_spent","wallet_credits" }

POST /api/ship/:id/provision ๐Ÿ‘ค โš“๐Ÿญmarketโ€‹

Stock the food / water tanks (life-support stores, separate from cargo/fuel); capped by the hull's food_cap_kg/water_cap_kg.

{ "food_kg"?: 4000, "water_kg"?: 5000 }
{ "ship_id","food_kg","water_kg","credits_spent","wallet_credits" }

POST /api/ship/:id/repair ๐Ÿ‘ค โš“๐Ÿญrepairโ€‹

Restore hp to max (50 โ‚ก/hp). โ†’ { "ship_id","hp","max_hp","credits_spent","wallet_credits" }

POST /api/ship/:id/transfer ๐Ÿ‘ค โš“โ€‹

Move cargo between the ship hold and the station hangar. Loading enforces the hull's cargo_cap_kg.

{ "item_type":"(id|code)", "qty":50, "direction":"hangar_to_hold"|"hold_to_hangar" }
{ "ship_id","item_type_id","qty","direction" }

POST /api/ship/:id/sell ๐Ÿ‘ค โš“๐Ÿญshipyardโ€‹

Sell the ship for 60% of hull base price. Requires an empty hold. Hull returns to the local yard's stock if the station backs a colony. โ†’ { "sold_ship_id","hull","credits_gained","wallet_credits","returned_to_yard","fleet_remaining" }


Outfittingโ€‹

All mutating refits are ๐Ÿ‘ค โš“๐Ÿญshipyard.

GET /api/ship/:id/loadout ๐Ÿ‘คโ€‹

โ†’ { ship_id, drive, drive_name, armor, hp, max_hp, hull, hull_size, slots, used_slots, weapons:[ { slot, weapon_id, name, class, damage, tier } ] }

Hull-size ladder: shuttle < light < gunship < cruiser < capital. Hardpoints by size: 1 / 2 / 3 / 4 / 6.

POST /api/ship/:id/armorโ€‹

{ "tiers"?: 1 } โ€” each tier +500 hp & max_hp, costs 5,000 โ‚ก. โ†’ { ship_id, armor, hp, max_hp, credits_spent, wallet_credits }

POST /api/ship/:id/driveโ€‹

{ "drive_type":"fusion_torch" } โ€” cost = 20,000 ร— drive tier. โ†’ { ship_id, drive, drive_name, credits_spent, wallet_credits }

POST /api/ship/:id/mountโ€‹

{ "weapon_id":"torpedo", "slot"?: 0 } โ€” cost = 10,000 ร— weapon tier. The weapon's min_hull must fit the hull; omit slot to use the lowest free hardpoint. โ†’ { ship_id, weapon_id, slot, credits_spent, wallet_credits }

POST /api/ship/:id/unmountโ€‹

{ "slot": 0 } โ€” refunds 5,000 ร— tier. โ†’ { ship_id, weapon_id, slot, refund, wallet_credits }


Crew & life supportโ€‹

GET /api/ship/:id/lifesupport ๐Ÿ‘คโ€‹

Age-scaled per-cycle ration need and how long the tanks last. โ†’ { ship_id, crew, food_kg, food_cap_kg, water_kg, water_cap_kg, food_need_per_cycle, water_need_per_cycle, cycles_of_supply, starve_cycles, starving } (cycles_of_supply = -1 when there's no crew.)

GET /api/ship/:id/crew ๐Ÿ‘คโ€‹

โ†’ { ship_id, crew:[ { character_id, name, role, age, status, wage_credits, share_bps } ] }

POST /api/ship/:id/crew ๐Ÿ‘ค โš“ (hire)โ€‹

Mints an NPC and berths them. Roles: pilot|engineer|gunner|medic|quartermaster|scientist|deckhand. Cap 8 active crew.

{ "role":"medic", "name"?: "Doc", "wage_credits"?: 0, "share_bps"?: 0 }
{ "character_id","name","role","ship_id" }

DELETE /api/ship/:id/crew/:character_id ๐Ÿ‘ค (fire)โ€‹

โ†’ { ship_id, character_id, fired:true }

POST /api/ship/:id/crew/:character_id/role ๐Ÿ‘คโ€‹

{ "role" } โ†’ { ship_id, character_id, role }


Stations & marketsโ€‹

GET /api/station/list ๐Ÿ”“โ€‹

โ†’ { count, stations:[ &lt;station object> ] }

GET /api/station/:id ๐Ÿ”“ (id|code)โ€‹

Full station object: { id, code, name, faction, sec_level, parent_body, orbit_radius_km, position, services[], fees{tax_bp,broker_fee_bp}, colony, ships_docked, open_order_count }.

GET /api/market/list ๐Ÿ”“โ€‹

Stations offering a market, with summaries. โ†’ { count, markets:[ { station, fees, open_order_count, items_traded } ] }

GET /api/market/:id ๐Ÿ”“ (id|code)โ€‹

A station's full order book, grouped per item with bids/asks and best bid/ask. โ†’ { station, fees, open_order_count, book:[ { item_type_id, code, name, base_price, best_bid, best_ask, bids[], asks[] } ] }

GET /api/market/resource/:id ๐Ÿ”“ (item id|code)โ€‹

Cross-market view for one commodity: where to buy (cheapest sells) and sell (highest buys). โ†’ { resource, best_buy_price, best_sell_price, buy_from:[ { station, best_price, total_qty, orders } ], sell_to:[ { station, best_price, total_qty, orders } ] }

GET /api/market/orders ๐Ÿ”‘โ€‹

The caller's own open resting orders. โ†’ { orders:[ { order_id, station, item, side, price, qty_remaining, qty_original, status, created_at } ] }

POST /api/market/buy ๐Ÿ”‘ ๐Ÿญmarketโ€‹

Instantly buy, crossing the cheapest asks (โ‰ค limit_price if given). Goods land in your hangar at that station.

{ "station":"(id|code)", "item":"(id|code)", "qty":100, "limit_price"?: 50 }
{ "filled","requested","credits_spent","avg_price","wallet_credits","delivered_to" }

POST /api/market/sell ๐Ÿ”‘ ๐Ÿญmarketโ€‹

Instantly sell from your hangar, crossing the highest bids (โ‰ฅ limit_price). โ†’ { filled, requested, credits_gained, avg_price, wallet_credits }

POST /api/market/order ๐Ÿ”‘ ๐Ÿญmarketโ€‹

Place a resting limit order with escrow (sell escrows goods, buy escrows credits).

{ "station","item","side":"buy"|"sell","price","qty" }
{ "order_id","side","price","qty","station","item","status":"open" }

POST /api/market/order/:id/cancel ๐Ÿ”‘โ€‹

Cancel your open order; refunds the escrow. โ†’ { ok:true, order_id, refunded_qty }


Inventoryโ€‹

GET /api/inventory/ship/:id ๐Ÿ‘คโ€‹

โ†’ { ship_id, name, cargo_cap_kg, used_mass_kg, items:[ { item_id, item_type_id, code, name, qty, unit, mass_kg } ] }

GET /api/inventory/station/:id ๐Ÿ”‘ (id|code)โ€‹

The caller's goods stored at a station hangar. โ†’ { station, items:[ โ€ฆ ] }


World (reads) ๐Ÿ”“โ€‹

GET /api/character/:idโ€‹

{ id, user_id, kind, name, archetype, religion, status, sex, age, home_colony, home_station, wallet, ship_count, crew_berth, created_at } ยท 404 if missing.

GET /api/colony/listโ€‹

{ count, colonies:[ { code, name, body, type, owner_corp, population, security, food_stock, station, corp } ] } (population desc).

GET /api/colony/:codeโ€‹

A colony plus trade: { produces:[], needs:[] }.

GET /api/faction/listโ€‹

{ count, factions:[ { id, code, name, description } ] }

GET /api/corp/list ยท GET /api/corp/:codeโ€‹

Corps; the fetch adds relations[] (corp_relations) and colonies[] owned.


Catalogs (reference data) ๐Ÿ”“โ€‹

EndpointReturns
GET /api/catalog/itemsevery item_types row (goods + hull stats)
GET /api/catalog/hullsships only โ€” hp, weapon, dry mass, cargo/food/water caps, price
GET /api/catalog/weaponsweapon catalog (class, tier, damage, range, guided, cooldown, ammo, min_hull)
GET /api/catalog/drivesdrives + their fuels[] and refuel_sources[]
GET /api/catalog/fuelsfuels + sources[]

Contracts (jobs)โ€‹

GET /api/contract/list?status=&type= ๐Ÿ”“โ€‹

Open contracts by default; filter by status/type. โ†’ { count, contracts:[ โ€ฆ ] }

POST /api/contract ๐Ÿ”‘โ€‹

Post a job. Escrows reward_credits from your wallet. Types: haul|mine|bounty|escort|salvage|supply.

{ "type","target"?,"pickup_location"?,"dropoff_location"?,"reward_credits","expires_at"? }
{ "contract_id","type","reward_credits","status":"open" }

POST /api/contract/:id/accept ๐Ÿ”‘โ€‹

Take an open contract (not your own). โ†’ { contract_id, status:"taken" }

POST /api/contract/:id/complete ๐Ÿ”‘โ€‹

Taker marks done and is paid the escrowed reward. โ†’ { contract_id, status:"done", reward_paid, wallet_credits }

Simplified: does not yet verify actual delivery (needs movement).

POST /api/contract/:id/abandon ๐Ÿ”‘โ€‹

Taker drops it; resets to open (escrow stays). โ†’ { contract_id, status:"open" }


Miscโ€‹

GET /healthz ๐Ÿ”“ โ†’ { ok:true, db:true }โ€‹

GET /ws ๐Ÿ”“ โ€” WebSocket upgrade (echo/hello for now; not yet a real channel)โ€‹


Ship objectโ€‹

Returned by GET /api/ship/:id and each entry of GET /api/ship/list. Keys are alphabetised (serialised from Postgres jsonb).

{
"id", "name", "status", // docked|flying|destroyed
"owner": { "character_id","name","kind","user_id" } | null,
"hull": { "id","code","name","category","base_price","hp","weapon" },
"station": { "id","code","name" } | null,
"position": { "x","y" }, "velocity": { "x","y" }, // FixedCoord mm, mm/s
"mass": { "dry_mass_kg","cargo_cap_kg" },
"propulsion": { "drive_type","remass_kg","fusion_kg","dv_used" },
"provisions": { "food_kg","food_cap_kg","water_kg","water_cap_kg" },
"combat": { "hp","max_hp","armor","last_aggro_at" },
"starve_cycles",
"crew": [ { "character_id","name","role","age","status","wage_credits","share_bps" } ],
"weapons": [ { "slot","weapon_id","name","class","damage" } ],
"created_at", "updated_at"
}

Not yet implementedโ€‹

Movement / flight (set-course, telemetry) ยท mining & prospecting ยท combat (attack, kill-feed) ยท refine/manufacture ยท NPC market-maker (books are hand-seeded) ยท life-support consume tick ยท real WebSocket channels + WS auth ยท OAuth callback ยท password-reset completion ยท pagination / idempotency / TLS.