Skip to content

Currency & economy

Currency is bookkeeping over coin — the tool tracks holdings and transfers, it never mints money. A holding is a Przedmiot entity whose @generyczne_nazwy resolves to one of the three Council denominations: Korony Elanckie (Gold, ×10000), Talary Hirońskie (Silver, ×100), and Kogi Skeltvorskie (Copper, the base unit). All wealth math runs in Kogi. This page covers the denomination ladder, listing holdings, creating and adjusting one, reconciliation, and the economy reports (Gini snapshot, timeline, materialization).

Currency reads need currency.read, writes need currency.write; economy reads need economy.read. The examples mint a coin holding for Lord Tussal (a character in the canonical session) and follow it through adjust and retire. Every example runs against a live daemon — see how the reference is tested.

Routes

Method Path Cmdlet Cap Write
GET /currency Get-NerthusCurrencyEntity currency.read
POST /currency New-NerthusCurrencyEntity currency.write
GET /currency/report Get-NerthusCurrencyReport currency.read
GET /currency/reconciliation Test-NerthusCurrencyReconciliation currency.read
GET /currency/denominations — (the denomination data table) currency.read
GET /currency/{name} Get-NerthusCurrencyEntity -Name currency.read
PATCH /currency/{name} Set-NerthusCurrencyEntity currency.write
DELETE /currency/{name} Remove-NerthusCurrencyEntity currency.write
GET /economy/snapshot Get-NerthusEconomicSnapshot economy.read
GET /economy/timeline Get-NerthusEconomicTimeline economy.read
GET /economy/materialization Get-NerthusMaterializationReport economy.read

Cap is the required capability ( = public, no token); Write () marks routes that pass the write gate; a in Cmdlet is reached directly, no wrapper. Paths are relative to /v1/api; the cross-cutting contract — middleware, envelopes, status codes — is on the API reference index.

The denomination ladder

GET /v1/api/currency/denominations returns the { count, items } envelope over the three Council denominations, each with its Kogi multiplier.

GET /v1/api/currency/denominations
Authorization: Bearer <token>
await fetch("https://evocation.nerthus.pl/v1/api/currency/denominations", {
  headers: { "Authorization": `Bearer ${token}` },
}).then((r) => r.json());

Response 200:

{ "count": 3, "items": [
  { "name": "Korony Elanckie", "short": "Korony", "tier": "Gold", "multiplier": 10000 },
  { "name": "Talary Hirońskie", "short": "Talary", "tier": "Silver", "multiplier": 100 },
  { "name": "Kogi Skeltvorskie", "short": "Kogi", "tier": "Copper", "multiplier": 1 }
] }

List holdings

GET /v1/api/currency returns the { count, items } envelope over every active coin holding. A fresh import seeds none, so the list is empty.

GET /v1/api/currency
Authorization: Bearer <token>
await fetch("https://evocation.nerthus.pl/v1/api/currency", {
  headers: { "Authorization": `Bearer ${token}` },
}).then((r) => r.json());

Response 200:

{ "count": 0, "items": [] }

Preview a holding without writing

?dryRun=true returns 200 { wouldCreate } and writes nothing — proven by the follow-up GET /currency, which still counts zero. wouldCreate echoes the denomination and owner exactly as sent.

POST /v1/api/currency?dryRun=true
Content-Type: application/json
Authorization: Bearer <token>

{ "denomination": "Korony", "owner": "Lord Tussal", "amount": 10 }
await fetch("https://evocation.nerthus.pl/v1/api/currency?dryRun=true", {
  method: "POST",
  headers: { "Content-Type": "application/json", "Authorization": `Bearer ${token}` },
  body: JSON.stringify({ denomination: "Korony", owner: "Lord Tussal", amount: 10 }),
}).then((r) => r.json());

Response 200:

{ "wouldCreate": "Korony (Lord Tussal)" }

Rejected: no denomination

A create body without a denomination is 400, nothing written.

POST /v1/api/currency
Content-Type: application/json
Authorization: Bearer <token>

{ "owner": "Lord Tussal", "amount": 10 }
await fetch("https://evocation.nerthus.pl/v1/api/currency", {
  method: "POST",
  headers: { "Content-Type": "application/json", "Authorization": `Bearer ${token}` },
  body: JSON.stringify({ owner: "Lord Tussal", amount: 10 }),
}).then((r) => r.json());

Response 400:

{ "error": "denomination required" }

Create a holding

POST /v1/api/currency resolves the free-text denomination to its canonical name and the owner to its canonical entity, then derives the holding name "<Denomination> (<Owner>)". The amount is the initial @ilość.

POST /v1/api/currency
Content-Type: application/json
Authorization: Bearer <token>

{ "denomination": "Korony", "owner": "Lord Tussal", "amount": 10 }
await fetch("https://evocation.nerthus.pl/v1/api/currency", {
  method: "POST",
  headers: { "Content-Type": "application/json", "Authorization": `Bearer ${token}` },
  body: JSON.stringify({ denomination: "Korony", owner: "Lord Tussal", amount: 10 }),
}).then((r) => r.json());

Response 201:

{ "Name": "Korony Elanckie (Lord Tussal)", "Denomination": "Korony Elanckie", "Owner": "Lord Tussal", "Amount": 10 }

List holdings, now one

The same GET /v1/api/currency after the create counts the new holding.

GET /v1/api/currency
Authorization: Bearer <token>
await fetch("https://evocation.nerthus.pl/v1/api/currency", {
  headers: { "Authorization": `Bearer ${token}` },
}).then((r) => r.json());

Response 200 (trimmed):

{ "count": 1, "items": [
  { "EntityName": "Korony Elanckie (Lord Tussal)", "Owner": "Lord Tussal", "Balance": 10, "Kogi": 100000 }
] }

Fetch one holding

GET /v1/api/currency/{name} resolves the holding by its entity name and returns its full projection — denomination, tier, owner class, balance, and Kogi value. The name is URL-encoded (spaces %20, parentheses %28/%29).

GET /v1/api/currency/Korony%20Elanckie%20%28Lord%20Tussal%29
Authorization: Bearer <token>
await fetch("https://evocation.nerthus.pl/v1/api/currency/Korony%20Elanckie%20%28Lord%20Tussal%29", {
  headers: { "Authorization": `Bearer ${token}` },
}).then((r) => r.json());

Response 200 (trimmed):

{ "EntityName": "Korony Elanckie (Lord Tussal)", "Denomination": "Korony Elanckie", "DenomShort": "Korony",
  "Tier": "Gold", "Owner": "Lord Tussal", "Class": "Physical", "OwnerType": "Postać", "Balance": 10, "Kogi": 100000 }

The holdings report

GET /v1/api/currency/report returns the { count, items } envelope and accepts ?owner= and ?denomination= filters (exact match). Here, the one holding owned by Lord Tussal.

GET /v1/api/currency/report?owner=Lord%20Tussal
Authorization: Bearer <token>
await fetch("https://evocation.nerthus.pl/v1/api/currency/report?owner=Lord%20Tussal", {
  headers: { "Authorization": `Bearer ${token}` },
}).then((r) => r.json());

Response 200 (trimmed):

{ "count": 1, "items": [
  { "EntityName": "Korony Elanckie (Lord Tussal)", "Owner": "Lord Tussal", "Balance": 10 }
] }

Adjust a balance

PATCH /v1/api/currency/{name} takes an absolute amount or a signed delta (mutually exclusive), or reassigns owner/location. Each change is a dated temporal append, so the holding keeps its balance history. Here delta: 5 adds five coins.

PATCH /v1/api/currency/Korony%20Elanckie%20%28Lord%20Tussal%29
Content-Type: application/json
Authorization: Bearer <token>

{ "delta": 5 }
await fetch("https://evocation.nerthus.pl/v1/api/currency/Korony%20Elanckie%20%28Lord%20Tussal%29", {
  method: "PATCH",
  headers: { "Content-Type": "application/json", "Authorization": `Bearer ${token}` },
  body: JSON.stringify({ delta: 5 }),
}).then((r) => r.json());

Response 200:

{ "Name": "Korony Elanckie (Lord Tussal)", "BalanceBefore": 10, "BalanceAfter": 15, "Owner": "Lord Tussal" }

Reconciliation

GET /v1/api/currency/reconciliation is a repo-wide integrity report: per-denomination supply plus warnings for negative balances, orphaned coin (a holder gone inactive or deleted), and asymmetric transfers. The single active holding raises none.

GET /v1/api/currency/reconciliation
Authorization: Bearer <token>
await fetch("https://evocation.nerthus.pl/v1/api/currency/reconciliation", {
  headers: { "Authorization": `Bearer ${token}` },
}).then((r) => r.json());

Response 200 (trimmed):

{ "WarningCount": 0, "Warnings": [], "EntityCount": 1, "Supply": { "Korony Elanckie": 150000 }, "CheckedAt": "2026-07-16T00:00:00.0000000Z" }

Economic snapshot

GET /v1/api/economy/snapshot computes the Gini coefficient over holder wealth and lists the top holders. With one holder the Gini is 0.

GET /v1/api/economy/snapshot
Authorization: Bearer <token>
await fetch("https://evocation.nerthus.pl/v1/api/economy/snapshot", {
  headers: { "Authorization": `Bearer ${token}` },
}).then((r) => r.json());

Response 200:

{ "Gini": 0, "HolderCount": 1, "TopHolders": [
  { "Owner": "Lord Tussal", "WealthKogi": 150000, "OwnerCategory": "Physical" }
], "ActiveOn": "2026-07-16" }

Economic timeline

GET /v1/api/economy/timeline returns a { count, points } monthly series (Gini, holder count, transaction count), built from applied-transfer dates and accepting ?from= / ?to= (YYYY-MM). With no transfers it falls back to the last six months.

GET /v1/api/economy/timeline
Authorization: Bearer <token>
await fetch("https://evocation.nerthus.pl/v1/api/economy/timeline", {
  headers: { "Authorization": `Bearer ${token}` },
}).then((r) => r.json());

Response 200 (trimmed):

{ "count": 6, "points": [
  { "Month": "2026-07", "Gini": 0, "HolderCount": 1, "Transactions": 0 }
] }

Materialization report

GET /v1/api/economy/materialization splits Kogi into physical (Postać-held) versus virtual (RP bookkeeping) per denomination and flags orphaned physical coin. Lord Tussal is a Postać, so his coin is physical.

GET /v1/api/economy/materialization
Authorization: Bearer <token>
await fetch("https://evocation.nerthus.pl/v1/api/economy/materialization", {
  headers: { "Authorization": `Bearer ${token}` },
}).then((r) => r.json());

Response 200:

{ "Denominations": [
  { "Denomination": "Korony Elanckie", "PhysicalKogi": 150000, "VirtualKogi": 0 }
], "OrphanedPhysical": [], "ActiveOn": "2026-07-16" }

Retire a holding (soft delete)

DELETE /v1/api/currency/{name} marks the block @status: Usunięty — never physical removal. Burned coin leaves supply, so the follow-up GET /currency counts zero again.

DELETE /v1/api/currency/Korony%20Elanckie%20%28Lord%20Tussal%29
Authorization: Bearer <token>
await fetch("https://evocation.nerthus.pl/v1/api/currency/Korony%20Elanckie%20%28Lord%20Tussal%29", {
  method: "DELETE",
  headers: { "Authorization": `Bearer ${token}` },
}).then((r) => r.json());

Response 200:

{ "softDeleted": "Korony Elanckie (Lord Tussal)", "status": "Usunięty" }