Formats
Every body the Exchange API sends or receives is described by a JSON Schema 2020-12 file. Each
schema is served, unchanged and without sign-in, at its permanent $id:
https://ingest.profit-base.online/exchange/v1/schemas/<name>.schema.json. A copy is on this site
under schemas, and every schema has valid and invalid
conformance fixtures.
Every request body is a JSON document sent with Content-Type: application/json; another media
type is 415 UNSUPPORTED_MEDIA_TYPE, and a body that is not a JSON document is 400 SCHEMA_INVALID
with one error at the pointer "". Neither answer is cached for its Idempotency-Key. The gateway
checks each body against its schema before it relays the request. A violation is
400 SCHEMA_INVALID with errors[], each a JSON Pointer and the violated keyword, at most 50.
Item reference — item-ref #
Names one catalogue entry: a blueprint product, an item, a material or a ship type. Send every field you know; the server takes the first field, in this order, that resolves to exactly one entry:
| Field | What it is |
|---|---|
bt |
The Basetool’s own key, as the feed and catalog/resolve answer it. Always wins. |
scRecord |
The DataForge record name (the scmdb tag), case-insensitive. Not unique. |
scGuid |
The game entity GUID. |
uexId |
The UEX id. |
locKey |
The global.ini name key without its @, case-insensitive. |
name + nameLocale |
The name as the game shows it. nameLocale is accepted; names are matched regardless of it, so prefer locKey for a non-English name. |
When no field resolves to exactly one entry, the first that resolved to several decides: the answer
is ambiguous with at most ten candidates {bt, name}. Fuzzy suggestions are always ambiguous,
even a single one, because they are never taken without the member. Store the bt the server answers
and send it from then on.
POST /exchange/v1/catalog/resolve resolves up to 500 references of one kind (BLUEPRINT,
ITEM, MATERIAL, SHIP_TYPE) at a time. A reference with a locKey whose key fields, the
locKey included, did not resolve to exactly one entry falls through to the name and adds a
LOC_KEY_UNRESOLVED warning at /refs/<i>/locKey.
Quantity — quantity #
{amount, unit}. unit is SCU or PIECE and must match the material’s own unit
(UNIT_MISMATCH otherwise). A PIECE amount is whole. An SCU amount may carry any number of
decimals: the server rounds it half-up to three before it stores or compares it, so expectedQuantity
12.3456 matches a stored 12.346. Send three decimals at most to see in the feed what you sent.
Quality — quality #
An integer from 0 to 1000. A material is stored at the quality the client sends, whatever its kind; send 0 when the quality is not known. An item has none and is stored at 0.
Place — location-ref #
A warehouse location, by uex: {kind: CITY | SPACE_STATION, id}, by exact name, or both; the
UEX link is tried first. The warehouse is the Basetool’s record of the org’s stock, the
Inventory area of the web app; its locations are the places stock and ships can be recorded at.
GET /exchange/v1/catalog/locations lists them. A place without a warehouse location is
LOCATION_UNKNOWN; it is never created.
Provenance — provenance #
{source, observedAt} with source one of log, manual, import, default, other. Send it
with a blueprint you add; the feed answers it for every blueprint whose source the Basetool
recorded. A default grant is the server’s alone, so a client’s default is stored as other.
Material kind — material-kind #
Read-only: {type: RAW | REFINED | NO_REFINE, commodity} and, where UEX knows the material, its
flags mineral, harvestable, raw, refined, buyable and sellable, so a client can route a
material to its own lists. commodity is true for a material listed in UEX’s commodity catalogue,
ores and refined metals included. None of it decides the quality; see
stock.
Offline file — envelope #
The wrapper of a file a client writes for the member:
{
"format": "basetool.blueprints",
"formatVersion": "1.0",
"generator": {"name": "Example Client", "version": "1.2.0"},
"generatedAt": "2026-09-27T12:00:00Z",
"items": []
}
An envelope carries no handle, player name, source folder or file path. basetool.blueprints is the
blueprint format: each item is {ref, acquiredAt?, provenance?}, at most 2000 per file. The member
can upload such a file in the web’s blueprint import, and a client can send the same document to
POST /exchange/v1/me/drafts/blueprints; both end in the same review.
- Size. The web import refuses a file larger than 8 MiB (8 388 608 bytes) before reading it; the draft route takes a body of at most 2 MiB.
formatVersion. Write1.0. Every1.xis read as this page describes; a later minor only adds optional fields. A major other than1is refused: the draft route answers400 SCHEMA_INVALIDwitherrors[{"pointer":"/formatVersion","message":"unsupported major version"}], and the web import refuses the file. The part before the dot must be exactly1, so01.0is refused too.- What is checked. The draft route checks the whole envelope against its schema and the major
version. The web import checks
format,formatVersionwhen it is present (it must be a1.x), and the items — at most 2000, each with aref— and ignoresgenerator,generatedAt,provenanceandextensions. Write files that pass the schema anyway. - Provenance. A blueprint taken over from the review is recorded with the source
import, whatever the item’sprovenancesays.
Extensions — extensions #
Where a schema allows extensions, it is an object of up to ten reverse-DNS keys
(io.github.example.client), each holding an object. The Basetool keeps them apart from its own
fields and never interprets an extension it has not registered.