GunSpec
Changelog

Changelog

Jede Änderung, die wir an API, Katalog und Website ausgeliefert haben, vollständig und neueste zuerst. Dieselben Einträge, die die Website als Karten zeigt und die API als JSON liefert, hier zum Lesen und Verlinken.

  • 61Veröffentlichte Einträge
  • 15. Sept. 2026Neuester Eintrag
  • 2. März 2026Erster Eintrag
  • 24Neue Funktionen

Dieselben fünf Kategorien, nach denen die API mit ?category= filtert. Breaking Changes sollten Sie vor einem Client-Upgrade lesen.

61 von 61 Einträgen. Jeder hat einen dauerhaften Link, den Sie in ein Ticket oder eine Commit-Nachricht einfügen können.

  1. Verbesserung

    The spec names the API you fetched it from

    Our OpenAPI document listed three servers - production, staging and a localhost address - on every environment.

    • One server, and it is the host that answered - generated clients and try-it consoles pick a server from that list, and neither of the other two was somewhere you should be sent
    • No internal hosts in the published contract - a staging URL is not a secret, but printing it in the document invites traffic at an environment hardened for us rather than for you
    • Local development still works - fetching the spec from a local API returns a document naming that API, so your tooling can call it

    If you generate a client from /openapi.json, regenerate it to pick up the corrected server list.

  2. Daten

    One spelling per value across the catalog

    A sweep of every catalog file against the schema that describes it found 1,418 records disagreeing with it. Filtering on any of these now returns the whole answer rather than half of it.

    • Second spellings merged - dao into double_action_only, striker into striker_fired, semi-rimmed into semi_rimmed, air_pellet into pellet, and twenty-six more
    • Countries stored as codes - 70 firearms named a country in words where a two-letter code belongs, including the historical states the catalog already codes elsewhere
    • 479 records promoted to their proper shape - entries written as a bare string where an object belongs, so adoptions and conflicts now carry the fields they always claimed to
    • Nothing was invented to fill a gap - a conflict recovered from a bare name gets its name and nothing else, because a field you can see is empty gets researched and one quietly filled does not

    Fields that legitimately hold more than a fixed list, such as barrel rifling, are now free text rather than being forced into six tokens that lose what somebody looked up.

  3. Funktion

    Values we serve match the lists we publish

    Eleven new checks hold the data against the vocabularies the API documents, so a value your client cannot parse is something we find rather than something you report.

    • Action types, trigger types, firing mechanisms, magazine types and adoption kinds are each checked against the published list
    • Failures name the values, not just the records - thirty-four records carrying nineteen spellings are nineteen decisions, so each check returns the distinct values and how many records hold them
    • Three vocabularies are newly published - firing mechanism, trigger type and magazine type were only ever enforced while a file was being written, and never against the catalog itself
    • Open lists stay open - a new mechanism is expected and still reported, so you can branch on the documented values without a new one breaking you

    Closed vocabularies are the ones a generated client parses strictly; those now have nothing outside them.

  4. Funktion

    See what the catalog has to show

    Data quality now reports visual coverage alongside field coverage, and firearms have a page of their own.

    • A new Firearms page under Data quality, with 18 checks covering duplicate names, missing chamberings, records that predate the company credited with them, and production years that contradict themselves
    • Media coverage by kind - line drawings, photographs, renders, 3D models and schematics counted separately, because a field count can never answer "does this record have a render"
    • Two counts, not one - how many records carry an asset of that kind, and how many files exist, since a record holding three renders is one record and three files
    • Attachments report their product photographs the same way, and a new check names every part that has none

    Every figure is read live from GET /v1/data/gaps, which is public and needs no key, so you can fetch the same report rather than taking the page's word for it.

  5. Ohne DatumVerbesserung

    Every tab on the reference is checked

    The cURL commands on the API reference have been executed against production nightly since the last release. The TypeScript and Python tabs beside them were not, on the reasoning that being generated from the spec meant they could not drift. That is an argument about the generator, not evidence that the request still resolves - so all six tabs now carry their own receipt.

    • The TypeScript and Python samples are executed too, each in the runtime you would paste it into: the fetch call by Node, the requests call by Python in a fresh virtualenv, exactly as printed with only the key substituted. Every tab carries its own badge, because the three can disagree - a sample naming a record the catalog no longer holds fails on all of them, while one that mishandles a response fails alone.
    • The first run found real bugs, which is the point. /health and /ready return a flat body, not the usual envelope, so the Python sample raised KeyError: 'data' and the TypeScript one printed undefined. The silhouette, media and image endpoints return a file by default, and all three tabs called res.json() on it. Samples now match the shape each endpoint actually returns.
    • The Unity, Unreal and GDScript tabs carry a new "Checked" badge. Those samples are fragments meant for a class, an actor or a scene, so there is no way to run one without wrapping it in code the page never showed you - and a badge over a wrapper we wrote would be worth less than none. Instead each is checked against the endpoint it is printed under: it must call that path, and carry a key wherever one is required. The badge says plainly that the sample is not executed.
    • Every result is published, including the ones that are not runs. GET /v1/examples/verification now returns all six languages, and each run says whether it was executed or a static check, so the two are never confused. Public and keyless, as before.

    The Verified page lists what each check prevents, and what it does not cover - including why the game-engine samples cannot be executed.

  6. Ohne DatumVerbesserung

    The blog is served by the API

    The six long-form guides on this site were React components compiled into the blog app. That meant GET /v1/blog answered an empty list while the site showed six posts, and a post published from the newsroom was invisible to anyone reading the API.

    • `GET /v1/blog` and `GET /v1/blog/{slug}` return the articles, the same records the site renders. Public and keyless, like the changelog.
    • A post published today is in the sitemap today. The sitemap and the prerenderer read the API instead of globbing source files, so a new article is crawlable as soon as it is published rather than whenever somebody remembered to add a file. Until now a CMS-published post was missing from the sitemap and served to crawlers as an empty shell.
    • Every published post passes the same content gate, including the two checks that matter to a reader: an endpoint a post cites has to exist in the API, and a gunspec.io link has to resolve to a real page. A dead citation is a support ticket from a developer who tried to call it.
  7. Ohne DatumFehlerbehebung

    BlogPost in the SDK matches what the API sends

    The TypeScript SDK's BlogPost type named four fields GET /v1/blog has never sent. Reading any of them returned undefined, and the fields that were actually there had no type at all.

    • `excerpt`, `heroImageUrl` and `publishedAt` are `summary`, `heroImage` and `postedAt`, which is what the endpoint has always sent. id is a string, not a number.
    • Four fields the endpoint sends were missing entirely: category, status, createdAt and updatedAt.
    • Nothing about the response changed. The payload is byte-for-byte what it was, so only the field names you read have to move. It breaks compilation rather than behaviour, which is the point: the old type compiled fine and gave you nothing.

    Fixed in @buun_group/gunspec-sdk 0.4.0. The Python package never carried the wrong names and is unaffected.

  8. Ohne DatumFunktion

    Check whether the reference is still true

    A reference can be stale without anything being down. Every documented operation is now called against the live API on a schedule and held against this documentation, and the result is published for you to read before you write the integration.

    • `GET /v1/contract` returns the most recent run with a verdict per operation: the status code, the media type, the schema, the envelope, the fields the reference promises against the fields actually sent, and the cache contract.
    • The plan gates are exercised, not assumed. Each gated endpoint is called with a key above it, at it, and below it, so a gate that has drifted downward - a Studio endpoint quietly answering a Builder key - is caught. That one is invisible from the outside: every other check passes while you are being given something you should not have.
    • This is not uptime. Whether the API is answering is GET /health and the status page. This is whether what it answers is still what the reference promises, which a perfectly available API can get wrong.
    • An API health panel in the docs renders the same run, endpoint by endpoint, so you can see it without writing a request.

    Public and keyless, cached for five minutes, and re-published immediately after each run.

  9. Ohne DatumFunktion

    The cURL samples are run too

    Every example on the SDK reference has been executed against the live API since the last release. The cURL commands on the API reference were not, which left the surface most readers actually start from as the one nobody had checked. All 129 of them now run the same way.

    • The command that runs is the command on the page. Each sample is executed exactly as printed, against production, with only the API key substituted at run time. A sample that stops working fails a build rather than your first paste.
    • A verified badge under every cURL block, saying when that command last ran and whether it passed, the same chip the SDK samples carry.
    • One place to read the receipts. GET /v1/examples/verification returns the most recent run for both surfaces and every language, with the outcome of each example. Public and keyless, like the SDK one: a proof only customers can fetch is a marketing line.
    • Examples that would write are never run against production. Each would create a real ticket, webhook endpoint or seller offer, so they are reported as skipped with that reason rather than quietly left out. The counts describe exactly what was executed.

    GET /v1/sdk/verification keeps working and is unchanged: the same rows through a second door.

  10. Ohne DatumVerbesserung

    The status page shows what we depend on

    When checkout is failing or an email has not arrived, the useful question is often not whether GunSpec is up. The status page now carries the platforms underneath us alongside our own surfaces.

    • Six dependencies, on the same board. Cloudflare, Stripe, Resend, Sentry, Discord and Groq, each with the same summary and per-day history as our own services.
    • The reading is what the vendor says, not whether their status page answered - a status host is the one thing that stays up during an outage. An indicator we do not recognise reads as unknown, never as a clean bill of health.
    • A vendor never sets our headline. "All systems operational" and the status pill in every footer count our own services only; somebody else's minor incident is not a GunSpec outage.
    • A dependency with no machine-readable feed is left out rather than guessed at. An absent row means we have nothing to report, not that everything is fine.
  11. Ohne DatumVerbesserung

    Images and 3D models answer If-None-Match

    The asset routes have always sent an ETag and never read one back. A revalidation was answered 200 with the whole file, which made the tag something you could store and never use - on the largest responses we serve.

    • `304 Not Modified` on the three asset routes. /v1/firearms/{id}/images/{imageId}, /v1/firearms/{id}/media/{selector} and /v1/firearms/{id}/model now compare your If-None-Match before the body is touched, and on an edge-cache hit as well. An unchanged image costs you a header exchange instead of a megabyte.
    • A 304 does not spend your daily allowance. It still takes a rate-limit slot, so caching saves real quota while abuse stays bounded. That was already true of the catalog endpoints and is now true of the assets.
    • Nothing to change. Store the ETag you are already being sent and send it back; a client that does not simply gets the file as before.
  12. Ohne DatumFunktion

    Every documented example is run before you paste it

    A code sample in documentation is a promise, and the only way to keep it is to run it. Every example on the SDK reference is now executed against the live API - the published package, a fresh project, the snippet exactly as the page prints it - nightly and after every release. The result is published beside the sample.

    • A chip under each example says when that snippet last ran and whether it passed, so you can check the claim before you copy it.
    • An Example verification page lists every result with its duration and a link to the CI run that produced it. It is public and needs no key: a proof only customers can fetch is a marketing line.
    • Writes are verified too, and nothing is left behind. Where an example creates something, its undo is also a documented example - webhooks.create mints an endpoint, get, update and test use the id it returned, webhooks.delete removes it - so five examples are checked and the account ends as it started. A write with no undo is published as skipped with the reason rather than quietly left out of the counts.
    • The badge vouches for the printed snippet. The sample is generated once and shared by the page and the runner, so what is verified and what you read cannot differ.

    Read it yourself at GET /v1/sdk/verification, which is keyless and cached for a minute.

  13. Ohne DatumVerbesserung

    The SDK reference is generated from the SDK

    The SDK pages in the docs were written by hand, and they had drifted the way hand-written reference always does. They covered 51 of the SDK's 131 methods, documented two that do not exist, and listed two error statuses on calls where the endpoint declares six. The page is now produced from the SDK packages themselves, so it describes the SDK you install.

    • Every method, from the source. All 131 methods across 22 resources, with their real signatures, parameters, return types and TSDoc prose, joined to the OpenAPI operation through the path each method actually calls. A method whose endpoint cannot be resolved fails our build, so a new call is documented or nothing ships.
    • The right errors, and the right tabs. Each method lists the statuses its operation declares rather than a guessed pair. The JavaScript and Python tabs on the API reference are generated fetch and requests calls - 53 of the hand-written ones had drifted into calling the SDK with Python method names inside a TypeScript block.
    • Versions and install commands come from the packages. Every npm install, pip install, import line, version number and release date on the docs is read from @buun_group/gunspec-sdk and gunspec at build time. The webhook event list is read off the API's own event enum.
    • One spec fix you may notice. GET /v1/me/favorites was documented as returning FirearmListItem. It returns FavoriteFirearm - the record plus favoritedAt - and now says so, which corrects the type in generated clients.
  14. Ohne DatumFehlerbehebung

    Stale subscriptions are reconciled with Stripe

    A paid plan whose billing period has ended while our record still says it is active is a Stripe webhook that never arrived. Those records are now reconciled with Stripe directly: once a day, and on demand from the console. A subscription that renewed has its record refreshed; one that ended, or that Stripe no longer holds, drops to Explorer and every API key on the account is re-rated at the same moment. Nothing waits on a webhook any more.

  15. Ohne DatumFehlerbehebung

    A lapsed plan ends on every path, not only the webhook

    When a subscription ended in Stripe but the webhook that reports it never reached us, the account kept its paid plan on the record and one of its API keys kept paid limits. Two things now hold whatever Stripe delivers:

    • An ended subscription mirrors as Explorer. Every place we read a subscription back from Stripe - the billing page, the staff console, a plan change - now records a cancelled or unpaid subscription as Explorer with no subscription attached, and re-rates every API key on the account at the same moment. Before, those reads updated the record and left the keys alone.
    • Staff can end a plan that Stripe already ended. An account whose plan has lapsed but still shows a paid tier can be returned to Explorer from the console, keys included. Only a plan Stripe is still billing is refused there, because the next webhook would put it back.

    If you cancelled and are still being served paid limits, that is this bug; it is closed, and your record is corrected the next time it is read.

  16. Ohne DatumFehlerbehebung

    format=svg works again on the silhouette endpoint

    A validation change on 11 September made GET /v1/firearms/{id}/silhouette refuse format=svg with a 400. That value was never documented, but SDK 0.1.x sent it as the name for the raw SVG file and the route had accepted it since the endpoint existed, so a client that had never failed started failing. svg is accepted again as the same thing as raw, on the endpoint and in the spec. If you are on SDK 0.1.x, upgrading is still worth it; you no longer have to.

    Alongside it, every validation failure now records which field it refused, so a report of "a 400 with no reason" can be answered from the log rather than by reproducing it.

  17. Ohne DatumVerbesserung

    A source hierarchy, not a source count

    The methodology page promised "4+ independent sources per firearm". That was never true of the whole catalog, and it measured the wrong thing: four retailer pages repeating one maker figure are one source. Both are fixed, and the fix is data rather than wording.

    • Every cited page is classed. provenance.sourceKinds on a firearm, cartridge or attachment is one { url, kind } per page in sources, and provenance.bestSourceKind is the strongest of them. The kinds are a new closed vocabulary, SourceKind, strongest first: manufacturer, standards_body, government, reference, aggregator, press, retailer, community, other. A maker or standards-body page is evidence for a figure; a retailer or forum page is evidence the item exists. A host we have not classed is other, never guessed. Additive, on every plan.
    • The hierarchy is written down. The docs' confidence page defines each kind, says which wins when two pages disagree, and states what the catalog holds today: the share of firearms citing at least one page, two or more, and a maker, standards-body or government page. Those figures are computed from the catalog at every build, and an unclassed page counts as the weakest kind, so the last one can only be understated.
    • The claims now match the data. The methodology page, the homepage and the FAQ no longer promise a source count or a review step the pipeline does not run. They say what each record carries, and quote the coverage figures above instead of a promise.

    SDKs 0.2.2 type sourceKinds, bestSourceKind and SourceKind in both languages.

  18. Ohne DatumVerbesserung

    Every record says where it came from, every fit says how sure we are

    Three additive changes to the API, and SDK 0.2.1 in both languages to match. Nothing that already worked changes shape.

    • `provenance` on every sourced record. Firearm detail, comparisons and family trees, cartridges and attachment detail now carry one provenance object: sources as an array of the pages consulted, dataConfidence, verifiedAt and verifiedFields (which fields a source actually stated; null while a row is still seed knowledge), specSource for cartridges, and the same updatedAt and version the record carries at the top level. Available on every plan: a consumer who cannot see where a figure came from cannot decide whether to trust it. The docs' field reference explains the confidence bands and which source wins when two disagree.
    • `source` on every fit. Compatibility answers already carried fitType, confidence and the interface chain in via; each fit item now also carries source, the weakest evidence behind it: curated (a person decided), universal (nothing to mount), or the least trustworthy interface row it passed through (inferred, inherited:parent, inherited:platform). A retailer or engineering integration can treat inferred as unverified on that one field; min_confidence hides it.
    • One named schema per vocabulary. Every closed value set in the spec (FirearmStatus, AttachmentStatus, MediaKind, TicketStatus, FitSource, InterfaceSource and the rest) is now a named component referenced wherever it appears, so a generated client gets one type instead of a union per schema. Two corrections landed with it: SupportTicket.status documents waiting, and DataReport.status now lists the values the API actually writes (pending, reviewed, resolved, dismissed). Seller listings document stockQty as nullable and the offer row as PublicOffer; a ticket's detail documents its replies and attachments; a firearm's manufacturer and category are documented as nullable, which they always were.

    SDKs 0.2.1 (npm @buun_group/gunspec-sdk, PyPI gunspec) type all of it, and their types are now generated and checked against the spec, so the two cannot drift again.

  19. Ohne DatumFunktion

    Trust pages for data collection, rights holders and media

    Four docs pages are new or rebuilt, each read off the same configuration the platform runs on, so the page cannot say one thing while the code does another.

    • Data collection, store by store. Under Trust, an inventory of what the platform collects, why, for how long and who else sees it, one entry per store with the field names as the code writes them. The retention figures come from the same table the purge jobs read. It also states where a model runs and what it reads, and the commitment that nothing a customer sends is used to train a model or sold for training.
    • A page for manufacturers and rights holders. What we publish about a product, what can be corrected or withdrawn, how to send the request, the windows we commit to (an acknowledgement with a reference within 3 business days, a decision within 10), what happens on the platform after a withdrawal, and the partner route instead. Copyright notices now go to a designated DMCA agent, and Sentry is listed among the subprocessors with what it sees: error reports from the website only, never from the API.
    • Media and drawings explained. How each silhouette, cartridge illustration, bullet diagram, photograph, schematic and 3D model is made, what it is drawn from, how to fetch it through /v1/firearms/{id}/media, and how it may be reused.
    • AI and LLMs, and Getting started, rebuilt. The agent page now covers the coding-agent packs, the workflow and rules they teach, the tool layer, the machine-readable files and the MCP position. Getting started is four steps from nothing to a list of firearms in your terminal, with the refusals you will meet on the way explained before you meet them.
  20. Ohne DatumFunktion

    New docs pages for versioning, paging, keys and errors

    The docs have six new pages, several rebuilt ones, and a sidebar grouped by what you are doing: getting started, plans and access, building, trust, and help.

    • A versioning promise, in writing. Every endpoint stays under /v1. New endpoints, fields, values and error reasons arrive without a new version, so ignore anything you do not recognise. A breaking change ships under a new prefix, and /v1 keeps answering for at least 12 months after it. The one exception, a fix to behaviour that is wrong, is announced here at least 30 days ahead, and every key that used the endpoint recently is contacted directly.
    • Authentication and pagination pages. Which operations need a key, the two headers that carry one, and how to rotate or revoke a key. How to walk a list so it works on every plan, how deep each plan can page, the sequential-page limit, and a table of every endpoint that pages.
    • Every error explained. The error page now lists every status, code and reason the API can send, each with what to do next. It is built from the API itself, so it cannot fall behind.
    • Plans compared properly. Plan cards with the three quota figures, a full feature comparison, and an endpoint access table grouped by section, with a filter and a copyable link to each row.
    • A field reference you can search. Filter the firearm fields by name, see each one's unit and whether it needs Builder, and read what every status and actionType value means.
    • Help in one place. A FAQ, a page covering every way to report a wrong figure or a missing record (including over the API), a "How we protect your data" page, and this changelog in full, with a category filter and a link to each entry.
  21. Ohne DatumVerbesserung

    Tighter security across the API and your account

    We reviewed every endpoint that accepts input for ways it could be misused, and closed what we found.

    • Support attachments stay with their ticket. Only the person who owns a ticket can list or add its files, a ticket holds up to 20, and HTML files are no longer accepted.
    • SVGs are sandboxed. Every SVG the API serves - silhouettes, bullet drawings, media - carries a policy that stops it running script if opened directly, and colour values written into a silhouette are validated and escaped.
    • Links are https only. Offer links, shop websites and data-report references must be https addresses.
    • Webhooks deliver only to public addresses. An endpoint is checked when you register it and again before every delivery.
    • Limits on size and pace. Oversized request bodies are refused before they are read, and actions in your account on the website are rate-limited per account.
    • Codes stay out of logs. Email-change verification codes are never written to our production logs.
  22. Ohne DatumFehlerbehebung

    Seller feeds of any size go through

    Several seller operations failed once a list grew past about a hundred items - and only in production, which is why they went unnoticed. They now work at any size up to their documented limits.

    • Pushing offers. PUT /v1/vendor/offers accepts its full 500 rows. A feed naming more than a hundred distinct items used to fail as a whole.
    • Bulk actions. Publishing, unpublishing, marking out of stock or deleting more than a hundred listings at once from Profile > Seller works.
    • Your stock in the catalog. GET /v1/attachments?vendor=...&only_offered=true works for shops stocking more than a hundred parts.
    • Fitment with offers, and traffic. Offers shown alongside fitment results, and the click totals for a full page of listings, no longer fail for larger shops.
    • Links stay https. Editing an offer's link now applies the same https-only rule as pushing it, and so does your shop's website address.
  23. Ohne DatumFunktion

    Docs you can hand to an AI, and a console that remembers

    The API docs are easier to use from a coding assistant, and the in-page console does more of the work for you.

    • Copy a page, or open it in your assistant. Every section can be copied as Markdown, or opened straight in Claude, ChatGPT or Perplexity with a prompt that points at a version of the page a model can read.
    • Pick any endpoint from the console. A searchable endpoint picker replaces the old sidebar, so the request itself gets the room.
    • Recent requests and share links. The console keeps your last twenty requests, and a link reopens it on the same endpoint with the same inputs, ready to send. Your API key is never saved in either.
    • Download a response. Save any response as JSON, YAML or CSV.
    • Less noise to start with. Paging parameters can be hidden from samples until you need them, long sections fold away, and samples that show several ways to call an endpoint split into tabs.
    • Honest answers without a key. A request sent from the docs with no key now gets the same 401 your own code would, instead of a generic block.
  24. Ohne DatumVerbesserung

    An API reference that matches the API

    We checked every documented endpoint against what the API actually returns, and fixed the reference wherever the two disagreed.

    • Every field described. Every property of every response now has a description, including nested ones such as imperial measurements and attachment fit details.
    • Accepted values and limits, spelled out. A parameter that takes a fixed set of values lists them in their own row, with its limits (length, range, pattern) beside it, so a request that would be refused is visible before you send it. The media selector, the silhouette's format, stroke_width and stroke_color, and every path id are documented this way.
    • Every status an endpoint can return. Server errors (500) and oversized requests (413) now appear in each endpoint's responses alongside 400, 401, 403 and 429.
    • Examples that return real data. Every example value is a real record from the live catalog, so a copied example returns results - /v1/firearms/ak-47/variants rather than a firearm with no variants, and real ids where a few examples named records that did not exist.
    • Cleaner samples. curl samples use long flags with one option per line, request bodies are pretty-printed, and every sample for an authenticated endpoint includes its key header.
    • Responses tidied. Support tickets and a few nested records no longer carry internal staff fields that were never part of the documented shape.
  25. Ohne DatumBreaking

    Five answers changed - check them against your integration

    Most of this release adds information. These five change an answer your code might already branch on.

    • 403, not 401, when the key is fine. A suspended account, a key no account owns (on /v1/me) and a key no shop names (on /v1/vendor) now answer 403. A 401 now always means the credential itself is missing, wrong or expired - so a new key can fix a 401 and cannot fix a 403.
    • Malformed JSON is a validation error. A request body that is not valid JSON answers 400 VALIDATION_ERROR with reason INVALID_JSON, instead of the undocumented HTTP_ERROR.
    • Webhook endpoints must be public https URLs. On the standard port, a hostname rather than an IP address, and no credentials in the URL. Redirects are no longer followed, so register the final URL, and a reply that does not finish within 10 seconds counts as a failed delivery.
    • `page` stops at 10,000. Beyond that you get a 400 instead of a failed request. At 100 a page, that is a million rows - further than any list goes.
    • Request bodies are capped. 1 MB for JSON bodies (support attachments allow more), refused before the body is read with 413 PAYLOAD_TOO_LARGE and the limit in maxBytes.
  26. Ohne DatumFunktion

    Every error tells you why

    Every error response now carries error.reason: one stable, machine-readable name for exactly what went wrong. error.code and every HTTP status stay as they were, so nothing you have built needs to change - but you no longer have to read the message to decide what to do next.

    • One reason per situation. A 401 used to say UNAUTHORIZED whether the key was missing, mistyped, switched off or expired. Now it says which: KEY_MISSING, KEY_INVALID, KEY_DISABLED or KEY_EXPIRED. The same goes for 403 (PLAN_REQUIRED, ACCOUNT_SUSPENDED, NOT_OWNER), 404 (ROUTE_NOT_FOUND for a wrong path, RESOURCE_NOT_FOUND for an id that does not exist) and 429 (RATE_LIMITED, DAILY_CAP_EXCEEDED).
    • The detail you need to act. PLAN_REQUIRED comes with details.requiredTier and details.currentTier, and INVALID_PARAMETER names each field that failed and why.
    • In the spec, not just the docs. ErrorResponse.reason is an enum in the OpenAPI document and every error response lists the reasons it can carry, so a generated client gets them as types.
    • Shown in every endpoint's examples. The error examples in the API reference now include the reason each one sends.

    Reason names are part of the contract: new ones may be added, existing ones will not be renamed.

  27. Ohne DatumFunktion

    Name a firearm, get an id

    Every endpoint here takes a catalog id, and until now the only way to get one from a name was search - which ranks a page of records about a query and never tells you how sure it is. That is fine for a person scrolling and wrong for anything automated: an agent has to pick an id before it can ask for a specification, and picking the top search hit is how the wrong barrel length ends up quoted with confidence.

    GET /v1/firearms/resolve?q= answers a different question. Which record is this name, and how sure are we.

    • Built for how people write. "G19 gen 5 MOS", "AK-47", "ak47", "H&K MP5", "Sig P226", "Česká zbrojovka" all land on the right record. Pass the words through unchanged - normalising them yourself only makes it harder.
    • Deterministic, not a model. An indexed lookup over the spellings a firearm answers to. Same query, same id, indefinitely - and it caches for an hour with an ETag, so the names you resolve most cost you nothing after the first time.
    • Ambiguity is an answer. "Glock 19" is several generations. You get status: "ambiguous", a null firearmId, and every tied candidate with its name and maker, because choosing for you would be guessing. "MP5" comes back the same way.
    • It tells you what it did not understand. unresolvedTokens holds the words no spelling accounted for - usually a variant the catalog does not hold. Being told is worth more than being handed the base model as though it were the answer.
    • A dead end is a 200, not a 404. status: "not_found" means the request was answerable and we hold no such record. Suggestions may come back marked match: "fuzzy"; they always score 0 and are never a resolution.
    • Fifty at once. POST /v1/firearms/resolve takes up to 50 names and returns results in the order sent, for pulling the firearms out of a document or a spreadsheet column without fifty round trips. Studio and above.

    Documented at https://docs.gunspec.io/en/api/firearms, and in the coding-agent packs, which now tell an agent to start here.

  28. Ohne DatumFunktion

    Webhooks that actually fire

    You can register a webhook endpoint on Studio and Enterprise, and until now subscribing to firearm.updated would have got you silence. Deliveries were only ever raised from the staff console, and the console is not where the catalog changes - the catalog is written by a seed job with no request behind it. The database now records every change itself, and a job turns those records into deliveries every quarter hour.

    • The events fire. firearm.created, firearm.updated, firearm.deleted, and the same three for manufacturers and cartridges. A change means the fields we serve actually moved - the same test that decides updatedAt, so your webhook and your If-None-Match can never disagree.
    • Three new events. firearm.variant.updated repeats the payload for records that have a parent, so you can follow a family without taking the whole catalog's traffic. firearm.source.changed and firearm.confidence.changed tell you when a figure's sourcing or confidence moved, which is a different question from "the spec changed" and used to be buried inside it.
    • The payload is the record. Byte for byte what GET /v1/firearms/{id} returns for your plan, version included, so a local mirror updates without a second call. A deletion carries the id alone.
    • Headers you can build on. X-Webhook-Id identifies the event and stays the same across retries, so it is the value to dedupe on. X-Webhook-Event and X-Webhook-Delivery name the event type and the individual attempt. X-Webhook-Signature is unchanged.
    • Retries now happen on their own. A failed delivery has always been scheduled to retry after 1, 5 and 15 minutes; nothing was running that schedule. Something is now.
    • One event instead of a flood. When the whole catalog is re-derived at once, you get a single catalog.resynced telling you to re-sync, rather than thousands of individual events arriving at your endpoint over several hours.
  29. Verbesserung

    Cache the catalog with confidence

    Keeping a local copy of GunSpec data is now something we encourage rather than something you have to guess at. Every catalog record tells you when it last changed and whether your copy is still current, and checking costs almost nothing.

    • A truthful `updatedAt` on every firearm, manufacturer, cartridge and attachment. It moves when the data moves and stays put when it does not, so re-importing an unchanged record no longer looks like an edit. The database maintains it itself, which means no future write path can forget to.
    • A `version` on every record - a short hash of the record's own fields. Equal versions mean equal data. It does not change with your plan, so it is the value to store beside a mirrored record.
    • Conditional requests across the catalog. Send back the ETag you were given as If-None-Match and an unchanged record answers 304 Not Modified with no body. A 304 counts toward your per-minute rate limit but not your daily allowance, so re-checking often is deliberately cheap.
    • A published cache policy at Docs > Caching: how long each kind of response may be kept, the reason behind every number, and the refresh loop to run against a local mirror. The table is generated from the same configuration the API stamps headers from, so it cannot drift from what you actually receive.
    • The contract is in the spec. ETag, Cache-Control, If-None-Match and the 304 now appear on every cacheable operation in openapi.json, so generated SDKs get the revalidation path for free. The coding-agent packs and llms.txt describe it too.
  30. Verbesserung

    Every part page is findable now

    A round of work on how search engines see the catalog. Most of this is invisible on the site itself and matters entirely for whether a page can be found from outside it.

    • 491 attachment pages carry real content - every part in the catalog was listed for search engines to visit, and every one of them answered with an empty page. They now arrive complete, with the specifications, the maker's description, and what the part mounts on stated in words rather than locked inside an interactive panel
    • Around 6,500 dead links removed - a firearm page listed related models by the id they would have, whether or not that record existed. Nearly every page in the catalog was quietly pointing at pages that were not there
    • Merged cartridges redirect properly - when two records for one cartridge were folded together, the old address kept answering with the survivor's content instead of saying where it had gone. Old links and bookmarks now land on the right record and say so
    • Spec sheets stopped appearing above the site - anyone arriving from a search result saw the plain search-engine version of the page stacked on top of the real one

    If you link to a part or an older cartridge address, those links behave properly now.

  31. Verbesserung

    A faster, cleaner page load

    Loading a page used to flicker through three states before settling, and browsing a gallery could stop images loading altogether. Both are fixed.

    • Pages settle in one step - a firearm, manufacturer, cartridge or part page painted a plain spec sheet, then a blank frame, then the real page. The plain version is what search engines read, and it now fades into the finished page instead of being torn out from under you
    • Browsing no longer rate-limits you - image files were counted against the same per-minute allowance as data requests, and a catalog page loads dozens at once. Scrolling far enough could stop images loading for a minute. Pictures no longer count against it
    • 3D models work in Firefox - a browser allows a limited number of live 3D views per page, and scrolling a grid of models allocated them faster than they were released, so the earlier tiles went blank. Each view now hands its resources back as it leaves the screen
    • A missing firearm shows one message, not two - asking for a record that does not exist stacked our "page not found" above the app's own, one over the other

    Nothing about what is on a page changed here, only how quickly and cleanly it gets there.

  32. Fehlerbehebung

    3D models load, line art is visible, and a phantom firearm is gone

    Three faults found in production, none of which showed up in development.

    • 3D models were refusing to load - the browser was blocking the decoder they need to unpack, and the textures inside them with it. Every model on the site was affected. The security policy now allows exactly that decoder and nothing more, rather than the blanket exception the browser's own error message suggests
    • Line art was invisible in several places - a firearm's drawing is a solid black silhouette, so on the dark listing rows in the seller console, the fit tables and the compatibility explorer it was a black shape on a near-black ground. It reads as light artwork now, the same as it always has on catalog cards and firearm pages
    • A firearm that does not exist was in the most-viewed table - a blank second row linking nowhere. Requests for one of our internal media endpoints were being counted as views of a firearm named after the endpoint, and it was outranking real records. Views are now checked against the catalog before they are recorded, and a view of something that is not in the catalog can no longer reach the table whatever wrote it

    The most-viewed counts for real firearms were never affected: the phantom row was extra, not a miscount.

  33. Funktion

    Compatibility, wherever you are in the catalog

    The engine that works out what fits what has been able to answer since it shipped, but only one page asked it. Now every page that raises the question can.

    • Firearm pages answer "what fits this" - a scrollable list of every catalogued part that mounts, with its photo, its maker and how the fit was established. It is in both the visual and the report view, and each part opens in a new tab so you keep your place. Previously a reader had to leave, open the explorer, and pick the same firearm again
    • Attachment pages answer the reverse - which firearms take this part, as a table with line art, maker logos and a link into each record
    • Start from a mount, not a gun - holding the part and not the firearm is the ordinary case for a builder, and there was no route for it at all. Pick a rail, a thread pitch or an optic footprint and see every firearm that carries it
    • The explorer opens on something - it used to be a header, four slugs printed as links, and then an empty screen down to the footer. There are now firearms to start from with their renders, mounts to browse, and a plain statement of what the page does

    Computing fit is still a Studio feature, and pages without it say so in a line rather than blocking what you came to read.

  34. Verbesserung

    Attachment pages read like spec sheets

    A part's page was a wall of loose label-and-value pairs with its mounting written out as a sentence. Everything below the header has been rebuilt around what a reader actually asks.

    • Specifications are a table - one column of labels, one of values, alternating rows. Four columns across meant a long material sentence stretched its row and left the three beside it as blocks of whitespace with nothing leading the eye back to the label
    • Units sit with their numbers - a spec written as "housing weight oz" was rendering as a heading that had lost its value, with a bare 7.4 underneath. It now reads 7.4 oz
    • Materials get their swatches, the same ones firearm pages use. A maker writes several materials in one sentence, so each is matched separately rather than colouring the whole string by whichever name happened to come first
    • Mounting is drawn - the rails, threads and footprints a part needs are shown with the catalogue's own illustration for each, laid out as the any-of and all-of groups they really are, and each one links through to the firearms that carry it
    • Provenance says something - data confidence is a labelled bar rather than a bare 0.85, and each source shows the page rather than just the site. A record citing a product page and the maker's homepage used to print the same line twice and look like a bug

    The maker and category line at the top is now a link and a tag rather than two words joined by a middot.

  35. Daten

    Cartridges drawn from real measurements

    A cartridge now has a record of its own instead of being a name repeated inside every firearm that chambers it, and the drawings are made from measured dimensions rather than guessed proportions.

    • One record per cartridge, 605 of them - there were 701 copies of .22 LR scattered through firearm files and nowhere to put a fact about the cartridge itself
    • Drawings that match the round - rim diameter and thickness, shoulder diameter, bullet length, case shape and material now come from the record. The .22 captive-bolt blank used to be drawn as a .22 Short with a bullet on it, and the .22 Hornet came out two millimetres too fat
    • Blanks look like blanks - a round with no projectile is drawn as one, with what seals its mouth shown instead, and military or industrial loads carry the tip and crimp colours they are actually bought by
    • 65 duplicate cartridges merged - .22 Long Rifle folded into .22 LR, 9x17mm Kurz into .380 ACP, 12.7x99mm NATO into .50 BMG, and so on. Old links and bookmarks still resolve to the surviving record
    • Sourced, and honest about it - every record says where its figures came from and how confident we are, and a figure nobody has checked against a manufacturer's own page is marked as such rather than presented as verified
  36. Verbesserung

    Seller endpoints have their own docs

    Everything a retailer needs was filed under compatibility, so the only way to find it was to scroll a reference about what fits what.

    • A Seller section in the API docs - every seller endpoint in one place, public reads and the private shop surface together
    • The bit nothing explained - how a key comes to belong to a shop. There is no such thing as a vendor key: you create an ordinary API key and the shop names it, and that is the entire arrangement
    • The rules that bite, stated up front - prices as whole minor units in currencies that do not all divide by 100, stock counts staying private, and writing to a listing counting as a claim that its price still stands
    • Links straight from your shop settings - each call in the console links to its own entry in the reference, landing on that one endpoint rather than the top of a page
    • Samples now come from the spec itself - example responses are generated from the same definition the API is built against, so a documented payload cannot drift from the one you actually receive
  37. Funktion

    Keep listings in sync from your own server

    The seller API could only ever be written to, which made two ordinary jobs awkward. Reading, updating one row, and finding your own shop ids are all possible now.

    • Read back what we hold - your listings with their SKUs, prices, stock counts, status and clicks. Read before you write and a nightly sync sends the twelve rows that moved rather than all four hundred
    • Change one price without resending the row - updating a price or a stock level used to mean re-sending the product id, the link and the currency too, which is how a script that only meant to reprice something silently rewrites its own link. Every field is optional now, and anything you leave out is untouched
    • Ask which shops your key can act for - an integration is handed a key, never a shop id, so there is now a call that answers it instead of somebody reading one out of the website
    • A key on two shops must say which - if you run several shops and name the same key on more than one, calls now name the shop rather than us picking. It used to take whichever shop was created first, so a push could land on the wrong storefront without saying so
    • Start by hand, add a feed later - the console and the API write through the same code, so a list you build by hand and a list a server pushes are the same list, with no SKUs to re-map when you switch

    Your key value is never sent to us. A shop names which of your own API keys it accepts a push from, and that mapping is the whole of it.

  38. Funktion

    See the traffic your listings earn

    A listing is what a seller pays their plan for, and until now there was no way to tell whether it was worth anything: our visitors arrived at your site indistinguishable from anyone else's.

    • A Traffic tab in your shop - clicks and distinct visitors over 7, 30 or 90 days, a chart of the daily run, and the listings that earned them
    • Clicks and visitors are counted separately - forty clicks from one person comparing prices is a different fact from forty people, and a number that only reports the first quietly overstates what the placement did
    • Per-listing counts - each row in your listings shows what it earned, so you can see which products actually move
    • Bots are not customers - crawlers following a listing are excluded, so the figure is people
    • Check it against your own analytics - we deliberately let your site see gunspec.io as the referrer for these visits, so you can hold our number up against yours rather than take our word for it

    Counting happens after the reader has already been sent on their way, so nothing about this slows down or stands between a customer and your shop.

  39. Funktion

    Where to buy, on every product page

    Attachment and firearm pages now show who stocks the thing you are reading about, and what they charge.

    • Near the top, not after the appendices - on a firearm page it sits directly under the header in both view modes. It used to be thirteen sections down, past every spec, which is no use to a reader and worthless to the shop
    • Firearms have it too - the section only ever appeared on attachment pages, though the data behind it covered both all along
    • Prices in the seller's own currency - formatted properly for the currency named, including the ones that do not divide by 100
    • Stock, without the numbers - a listing says in stock or no stock at this supplier. What a shop holds is their business, so we store the count and never publish it
    • Quiet when nobody stocks it - the section renders nothing at all rather than showing an empty heading that reads like a page which failed to load

    We never take the order. Every listing links out to the shop's own page, and nothing here holds a basket, a payment or a customer.

  40. Funktion

    Sell on GunSpec

    Shops on an Enterprise plan can now list what they stock against the parts and firearms in our catalog, and manage the whole list from their profile. No integration required to start.

    • Apply, and watch the application - applying is a record now rather than an email, so it lands in a queue a person reviews and you can see where it stands. You get a reference code and a link to track it, and applying on a lower plan no longer loses your application
    • Build a list from our catalog - search parts and firearms with their photos and renders, select several at once, set a price and a stock count, then publish. Nothing is public until you publish it, and a listing is written as a draft first
    • Import a whole catalog as JSON - drop in one file or several, see exactly what would be created, changed or skipped before anything is written, and download a template to start from. A bad row is reported on its own rather than refusing your file
    • See what a reader will see - every row shows your logo, your formatted price and the in-stock line exactly as they appear on the product page, next to the fields that change them
    • Run more than one shop - a group trading under two names, or a storefront per market, can hold several shops on one account and switch between them
    • Nothing goes stale quietly - a hand-kept list stands for 90 days and a feed for 30, with a countdown showing which listing lapses first and a one-click way to say your prices still stand. We email you a fortnight before anything drops off
    • A lapsed plan hides your shop, it does not delete it - if a payment fails or you downgrade, your listings stop appearing and everything stays exactly where you left it. Renew and it is all back, prices and stock included, with nothing to set up again
  41. Fehlerbehebung

    You stay signed in, and 3D models load again

    Signing in was more fragile than it looked, and every 3D model on the site was quietly broken.

    • A deploy no longer signs you out - the app asked "who is signed in?" and treated any failed answer as a definite "nobody", so the few seconds a server takes to restart looked like a mass logout. Only a real rejection signs you out now; a server error or a network blip leaves you exactly where you were, and the first check retries across the gap
    • A dropped cache is no longer a logout - your session lived in a single cache entry, and that cache takes a moment to agree with itself between data centres, so you could be told your session had expired when it had not. The session is now a durable record with the cache in front of it, and a miss is rebuilt instead of ending your day
    • The site and the staff console keep separate sessions - signing into one no longer ends the other
    • Access ends when it is supposed to - deleting an account used to leave its existing sessions usable for up to 30 days, because the wrong entry was being cleared. Support sessions opened on a customer's behalf are now marked read-only from the moment they are created, and their 30-minute limit is recorded where it is actually enforced rather than only in the cache
    • 3D models load again - every firearm model had been answering "not found": the files were lost in a reorganisation while the catalog went on pointing at them, so the gallery's 3D view, the viewer on a firearm's page and the rotating card thumbnails all had nothing to show. They are back, and about 82% smaller than before, so a wall of them costs a fraction of what it would have. GET /v1/firearms/{id}/model now serves the same files to API subscribers, including models added through the staff console, which were unreachable until now

    Nothing about how you sign in has changed - only how well it holds.

  42. Verbesserung

    Catalog images show up, and load lighter

    A firearm's imagery was being hidden by the site in one place and sent at full size in another. Both are fixed, and the 3D models now have a wall of their own.

    • About a thousand firearms got their picture back - a catalog card only showed imagery when a firearm had two or more images, so every firearm holding a single render fell through to the "no image" placeholder. The catalog looked like it was mostly line art when it was not
    • Pages load around forty times lighter - grids now ask for a thumbnail rather than the full 1536x1024 render. A gallery page of sixty tiles went from roughly 29MB to 668KB, and a repeat view of the same image is answered from the edge instead of being fetched again
    • Renders lead, drawings follow - cards, the firearm page and the similar-firearms strip all open on the photograph or render where one exists, with the silhouette a click away. Ask for line art in your media preference and it still leads
    • 3D models are their own gallery view - browse every firearm we have modelled, each tile turning as you scroll past it
    • A model is no longer filed as a photograph - eight models had been recorded as pictures. They were reaching the image wall as tiles that could never draw, and one showed as an empty frame on its card

    Nothing was removed from the catalog - this is only about which images you are shown, and how much you download to see them.

  43. Verbesserung

    Browse filters are faster

    Filtering the catalog was doing more work than it needed to, and the site can now tell you when something is going on.

    • The browse facets are indexed - /v1/firearms accepts fifteen filters and only four of them were indexed. Action type and country of origin - the two the browse UI puts in front of you - each cost a full scan of the catalog, once for the page and again for the result count
    • Result counts stopped scanning - the total on a filtered list is now a seek rather than a walk of every row
    • Site-wide notices - planned maintenance and service messages are published to a banner with a real end date, so a notice comes down when it stops being true instead of when somebody remembers it. Dismiss one and it stays dismissed; a new one still reaches you
    • Report an issue from a firearm page - a link on the spec table for when a figure looks wrong

    Filtering and counting return exactly what they did before - only faster.

  44. Funktion

    Image galleries and a media API

    Firearm imagery is now browsable properly on the site and reachable directly from the API.

    • A gallery you can page through - open any image full size, move with the arrow keys, and see where you are in the set
    • Attribution you can copy - one click puts the credit line on your clipboard. Images are free to use commercially; API subscribers may use them without attribution, everyone else credits gunspec.io wherever the image appears
    • AI-generated renders are labelled - a render and a photograph are no longer presented as the same kind of thing
    • Three new endpoints - GET /v1/firearms/{id}/media lists every asset for a firearm, /media/{selector} fetches one by role, and /images/{imageId} fetches one by id. All three are public and need no key
    • Alt text and dimensions are returned - the API had always carried them, but they were missing from the published types, so nothing downstream could read them

    No existing endpoint changed shape, and nothing was removed.

  45. Funktion

    Ballistics charts show the whole trajectory

    The trajectory chart on every firearm page has been rebuilt, and the numbers behind it are now readable as a table.

    • Four metrics on one axis - velocity, energy, momentum and energy density are each plotted against their own muzzle peak, so curves in different units stay comparable instead of collapsing against the largest one. Hover any point for the real value in its own unit
    • A drop table under the chart - the same sampled points as rows, near range by default and the full range on request, each retained metric carrying a hairline bar showing how much of the muzzle figure survives at that distance
    • Transonic and effective range marked - the chart shows where the projectile drops through Mach 1.2, where it passes the effective range, and which curves are duplicates of one another rather than drawing them twice
    • Cartridge diagrams resize - small, medium or large, so a case drawing can be read on a phone without pinching

    Every figure is computed from the load data already behind GET /v1/firearms/{id}/load - nothing about the underlying ballistics changed, only how much of it you can see.

  46. Fehlerbehebung

    Subscriptions activate right after checkout

    A completed checkout could leave your plan unapplied, and several pages would not open from a direct link. Both are fixed.

    • Your plan applies immediately - finishing checkout returns you to your billing page with the new tier and its rate limits already active, instead of dropping you on the home page with nothing changed
    • Direct links and bookmarks work again - profile, sign in, sign up, onboarding, changelog, store and shared collection links open straight to the page, including on a hard refresh or in a new tab
    • German pages restored - every /de page loads again instead of returning a not-found
    • Support ticket API docs corrected - the documented categories, statuses and sort options now match what the API actually accepts, so a request built from the spec no longer comes back as a 400

    If a recent checkout did not apply your plan, your account has already been corrected - nothing to do at your end, and no one was charged twice.

  47. Verbesserung

    Catalog figures are accurate everywhere

    Different parts of the site quoted different catalog sizes, and all of them were out of date. They now come from one source and agree.

    • Real numbers, not estimates - pages that advertised "150+", "400+" or "4,900" firearms now state the actual catalog size
    • Documentation matches reality - sample responses and stats in the API docs reflect the live dataset rather than hand-maintained figures
    • Counts stay current - figures are read from the live stats endpoint where possible, and regenerated from the catalog at build time for pages that cannot wait on a request

    If you were sizing the dataset from our marketing pages, it is considerably larger than those pages claimed.

  48. Verbesserung

    Email confirmations for what you do

    Actions that previously happened silently now leave a paper trail in your inbox.

    • Support tickets - you get a confirmation when you raise a ticket and when a reply lands, so you are not refreshing the page to check
    • Data corrections - reporting a spec error is acknowledged, so you know it reached us
    • Welcome on signup - a first-time signup gets a welcome email alongside the login code
    • Email preferences - turning a subscription on or off is confirmed in writing, so the change is never ambiguous

    Newsletter confirmations are now sent only on a real change, so opening the confirmation link twice - or having your mail client prefetch it - no longer sends you a duplicate.

  49. Fehlerbehebung

    Store purchases always deliver, and never charge twice

    A store purchase could be charged without the pack ever being granted, and the same pack could then be bought a second time. Both halves of that are fixed.

    • Your pack is granted every time - fulfilment is now matched on an identifier known before payment starts, so a fast payment confirmation can no longer arrive before the order is ready and silently do nothing
    • No second charge for something you already bought - returning to the store settles any in-flight purchase before checking what you own, so a payment still settling no longer reads as "not owned"
    • Interrupted checkouts recover themselves - reopening the store completes a purchase that was paid for but not delivered, with no need to contact us
    • Failed deliveries retry instead of disappearing - a delivery that cannot find its order now reports the failure so it is retried, rather than reporting success

    If you were charged for a pack you never received, it will be granted the next time you open the store.

  50. Funktion

    SDK adds content, collections and catalog helpers

    Both the TypeScript and Python SDKs gained new resources, at parity with each other.

    • Content - listChangelog, getChangelogEntry, listBlogPosts and getBlogPost, so you can surface our updates and articles in your own app
    • Collections - getShared resolves a shared collection by its share id
    • Firearms helpers - listIds for a bare id set, getSchematics for a model's diagrams, and popular for trending entries
    • Stats - catalogCoverage reports how complete the catalog is by field

    All additive - no existing method signatures changed, so upgrading will not break your integration.

  51. Fehlerbehebung

    Search handles calibers and brand names correctly

    Searching for anything containing a dot, an ampersand or a slash was quietly returning a fraction of the matching firearms. That is fixed.

    • Caliber searches work - .45 ACP returned 10 results where 834 matched; .22LR and 5.56x45 returned none at all
    • Ampersand brands work - H&K MP5, S&W and M&P now match the models you would expect instead of an unrelated spread of the catalog
    • Accented names match themselves - names like Búfalo and Škorpion are no longer stripped of their accents before searching
    • Long queries no longer fail - a search phrase over about 48 characters returned a server error rather than results

    Nothing changes in how you call the endpoint - the same query strings simply return the right firearms now.

  52. Funktion

    Manage your billing from your profile

    Billing is now self-serve. Everything that previously meant a trip to the Stripe portal, or an email to us, is on your profile page.

    • Saved payment methods - add, remove and set a default card without leaving the site
    • Invoices and receipts - your full billing history in one list, with a PDF download for every item, including store pack purchases
    • Change plan in place - upgrade or downgrade without a checkout redirect, with the proration shown before you confirm
    • Cancel and resume yourself - cancellation states the exact date access ends, and you keep your plan until then

    Documents are generated from Stripe's own figures, so a receipt always matches what was actually charged.

  53. Daten

    1,749 more firearms in the catalog

    The catalog has grown from 4,907 to 6,656 firearms, now spanning 759 manufacturers and 540 distinct calibers.

    • Every category deeper - 437 rifles, 392 pistols, 190 shotguns, 173 machine guns, 142 carbines, 128 submachine guns, 115 revolvers, plus assault and battle rifles
    • Six centuries of coverage - entries now run from 15th-century hand cannons through to 2026 SHOT Show releases
    • Broader maker coverage - the largest additions land under Colt, Remington, Winchester, Springfield Armory, Heckler & Koch and Smith & Wesson
    • Accuracy pass alongside the additions - roughly 1,700 existing records were revised, including corrected manufacturer attributions and spec fields normalised to their proper types

    Everything is available through the same endpoints and SDK methods you already use - no changes needed on your side.

  54. Fehlerbehebung

    Stability and polish fixes

    A round of fixes from your reports and our own testing.

    • No mobile overflow on blog posts, which no longer scroll sideways on phones
    • Author avatars load reliably from the brand CDN
    • Cleaner rendering with code-block and static-post warnings resolved
  55. Funktion

    Live status page

    You can now check service health at a glance.

    • Public status page showing the API, web app and asset CDN in real time
    • Footer status pill on every page that reflects current uptime
    • Health probes across our workers so incidents surface fast
  56. Verbesserung

    Faster, richer firearm pages

    Every firearm page got a modern rebuild.

    • Cleaner detail layout with a shared firearm card used consistently across the catalog
    • Live catalog coverage so specs, calibers and related models stay in sync
    • Quicker to scan with tightened typography and a clearer information hierarchy
  57. Funktion

    Developer blog

    We launched a blog for guides, deep dives and product updates.

    • Long-form articles covering calibers for developers, comparing firearms programmatically, and building game weapons from real data
    • Built for sharing with rich social cards, copy-link and share targets, plus a table of contents that follows along as you read
    • Fast and searchable with category filters and SEO-friendly pages
  58. Verbesserung

    Friendlier changelog controls

    The changelog got a full editorial redesign, plus friendlier controls and per-category visuals.

    What changed

    • Animated covers every entry now leads with a generative pixel-shader cover, tinted and styled per category.
    • Dedicated pages each entry has its own page at /changelog/{slug} with the full write-up, code and tables.
    • Refresh throttle the refresh button now allows 3 taps per minute, then a 60-second cooldown with a live countdown.

    Category styles

    Each category renders its own shader and icon, so the timeline reads at a glance:

    CategoryShaderTint
    Featureplasmagreen
    Improvementgridblue
    Bugfixmatrixamber
    Databarsviolet
    Breakingwavesred

    For developers

    The same data powers the public API and the RSS feed. Pull the latest entries:

    bash
    curl "https://api.gunspec.io/v1/changelog?per_page=5"
    Tip: subscribe via RSS to get notified the moment something ships.
  59. Verbesserung

    A cleaner mobile experience

    We went through GunSpec.io on small screens and tightened things up:

    • Bottom-sheet dialogs - search, filters and pop-ups now slide up from the bottom on phones, the way a native app does
    • No more overflow - the header, stat blocks and footer fit small screens instead of pushing content off the edge
    • Scrollable reference tables - the API reference parameter and response tables drag sideways on mobile, and code samples switch to a language dropdown so they never overflow

    Nothing changed on desktop - this is a mobile-only polish pass.

  60. Funktion

    Visual gallery: feature icons, silhouettes and photos

    Browse the catalog visually from one place. The new Gallery hub at /gallery brings three views together:

    • Feature icons - every spec feature (optics, actions, safeties and more) rendered as a clean icon, searchable by name
    • Silhouettes - line-art profiles for the whole catalog
    • Photos - real firearm photography, with a per-model viewer that lists the source, author and licence for each image

    Everything is searchable and filterable, and the old /features page now opens straight into the gallery.

  61. Funktion

    Changelog & What's New Feed

    We added a dedicated changelog so you can follow what's happening with GunSpec.io in one place.

    • Public changelog page at /changelog with category filters and search
    • RSS feed at /changelog.xml - subscribe with any RSS reader to get updates automatically
    • Admin CMS for managing entries with draft/publish workflow
    • Discord notifications - new entries are posted to our Discord on publish

    Subscribe via RSS to stay in the loop, or just bookmark the changelog page and check back anytime.

Vier Wege, von einer Änderung zu erfahren, von einer Seite zum Lesen bis zu einem Ereignis, auf das Ihr Code reagieren kann.