GunSpec
Standing

Experience and levels

Every successful call earns experience for the account that made it, weighted by what the call was. The intent is to recognise how deeply you have integrated rather than how much traffic you send, so the calls you only make once you have built something are worth several times a page of a list.

Read from the table the API writes from, so this page cannot fall behind it. 20 operations are worth more than the floor; everything else earns 1.

OperationWhat it isWorth
GET /v1/attachments/{id}/firearmsList firearms an attachment fits8
GET /v1/firearms/{id}/attachmentsList attachments that fit a firearm8
GET /v1/firearms/{id}/interfacesGet a firearm's mount interfaces8
GET /v1/firearms/head-to-headCompare two firearms head to head8
GET /v1/firearms/resolveResolve a name to one firearm8
POST /v1/firearms/resolveResolve many names at once8
GET /v1/ammunition/{id}/ballisticsCompute a ballistic table5
GET /v1/calibers/{id}/firearmsList firearms in a caliber5
GET /v1/calibers/ballisticsGet a caliber ballistic profile5
GET /v1/calibers/compareCompare calibers5
GET /v1/firearms/{id}/calculateCalculate ballistics for a firearm5
GET /v1/firearms/{id}/similarFind similar firearms5
GET /v1/firearms/{id}/variantsList variants5
GET /v1/firearms/compareCompare firearms5
GET /v1/firearms/searchFull-text search3
GET /v1/ammunition/{id}Get an ammunition load2
GET /v1/attachments/{id}Get an attachment2
GET /v1/calibers/{id}Get a caliber2
GET /v1/firearms/{id}Get a firearm2
GET /v1/manufacturers/{id}Get a manufacturer2
Every other operationA page of a list included. Paging is how a mirror is built, which is fine, and not a demonstration of anything.1

Experience recognises something you built, so it is earned by the clients that do the building. The kind is read from your User-Agent, the same way the request log records it.

ClientEarnsWhat it is
sdk-typescriptyesThe TypeScript SDK.
sdk-pythonyesThe Python SDK.
mcpyesThe hosted MCP server.
http-toolyescurl, Postman, HTTPie and the like: somebody trying it for real.
http-libraryyesAn HTTP client inside your own code.
unknownyesA runtime that sends no agent. Far likelier to be your integration than a browser.
browsernoA browser earns nothing.

Two other calls earn nothing. A 304 Not Modified earns nothing, on the same reasoning that it spends none of your allowance: the polite integration must not be the expensive one, and caching is what we would rather you did. A call that failed earns nothing either, so guessing at ids pays nothing.

Your level follows from your total and nothing else. Each level costs a little more than the last, so the early ones come quickly and the later ones are earned. The days column is what it would take at the ceiling of 500 a day, which a real integration never meets.

LevelStarts atCostsDays at the cap
1000
250501
32001501
44502501
58003502
61,2504503
71,8005504
82,4506505
93,2007507
104,0508509

Two figures beside the level, both counted rather than earned. There are 145 documented operations to meet.

Breadth

operationsUsed is how many you have called at least once, against operationsAvailable. Counted by a nightly job from the request log, so an operation you call for the first time today appears tomorrow. It costs nothing on the request path, which is the point.

The streak

streakDays is consecutive days you have called at all, and daysActive is the total. Yesterday still counts as unbroken, so a timezone does not cost you a streak. Neither pays experience: a bonus for showing up rewards the calendar rather than the integration.

GET /v1/me/usage returns a progress block beside the usage counters: xp, xpToday, dailyXpCap, level, levelStartsAt, nextLevelAt, and the breadth and streak figures above. The two level bounds are there so a client can draw the bar without knowing the formula.

FieldWhat it means
xpExperience earned across every key on the account, for its whole life.
xpTodayExperience earned today (UTC).
dailyXpCapThe most one key can earn in a UTC day. A ceiling rather than a target: reaching it every day is not how the levels are meant to be climbed.
levelYour level, derived from xp alone. Nothing else moves it.
levelStartsAtThe experience this level began at.
nextLevelAtThe experience the next level begins at.
streakDaysConsecutive days you have called the API, counting today. A day you did not call breaks it, though yesterday still counts as unbroken so a timezone does not cost you a streak. Reported, never rewarded: no experience is paid for showing up.
daysActiveDays you have called the API at all, over the last two years.
operationsUsedDocumented operations you have called at least once. Counted from the request log by the nightly job, so an operation you called for the first time today appears tomorrow.
operationsAvailableDocumented operations there are to call, counted from this document rather than written down, so it cannot fall behind a route added today.