---
title: "List manufacturers"
method: GET
path: "/v1/manufacturers"
tags: ["Manufacturers"]
---

# List manufacturers

`GET /v1/manufacturers`

## Request

- Base URL: `https://api.gunspec.io`
- URL: `https://api.gunspec.io/v1/manufacturers`
- Auth: one of:
  - API key in header `X-API-Key`
  - HTTP bearer

Returns a paginated list of firearm manufacturers.

Available on every plan. Requires an API key; Explorer keys receive a reduced field set.

## Query parameters

- `page` integer
- `per_page` integer
- `country` string
- `search` string

## Headers

- `If-None-Match` string

## Response `200`

List manufacturers

- object
  - `success` boolean, required: Always true on a successful response. Every error carries `false` and an `error` object instead.
  - `data` Manufacturer[], required: One page of results. Use `pagination` to walk the rest.
    - `id` string: URL-safe slug identifying the manufacturer, e.g. `glock`.
    - `name` string: Display name, as the maker writes it.
    - `countryCode` string, nullable: ISO 3166-1 alpha-2 code of where the company is based.
    - `foundedYear` integer, nullable: Year the company was founded.
    - `status` 'active' | 'defunct' | 'unknown' | 'null', nullable: Whether the company still trades. Much of this catalog is historical, and null means nobody has established which.
    - `defunctYear` integer, nullable: Year the company ceased trading, where that is established. Null while it still trades, and also null where the closing year is simply unknown, so an absent value is never read as "still trading".
    - `stateOwned` boolean, nullable: Government owned. **Null is not false**: it means nobody has established it, and a consumer treating null as false would report every unchecked company as private.
    - `makesFirearms` boolean, nullable: Builds the products this catalog lists, as against importing, rebranding or customising them. Scope is the catalog rather than a legal definition: air rifles are listed here as rifles and pistols, so their makers are true. Null means unestablished.
    - `parentId` string, nullable: The manufacturer that owns this one today.
    - `predecessorId` string, nullable: The manufacturer this one succeeded, which is not the same as being owned by it: U.S. Repeating Arms followed Winchester without Winchester owning it.
    - `website` string, nullable: Official website, where one is known.
    - `logoUrl` string, nullable: Absolute URL of the logo, or null where none is on file.
    - `description` string, nullable: Prose summary of the record, where one has been written.
    - `createdAt` string: When the record was first added, `YYYY-MM-DD HH:MM:SS` in UTC.
    - `updatedAt` string: When a field we serve last changed. Maintained by the database rather than by whatever wrote the row, so it moves for a corrected specification and does not move for a re-run of the importer.
    - `version` string, nullable: Opaque fingerprint of this record. It changes when and only when a field we serve changes, so a client holding the same value already has the record and need not fetch it. Equality is the only supported operation: do not parse it, and do not assume how it is computed. Null means the record has not been written since versioning began, not that it is unchanged.
  - `pagination` Pagination: Page-size is reported under both `per_page` (matching the request parameter) and `limit` (retained for existing integrations). They always carry the same value. `total` and `totalPages` are omitted for Explorer and anonymous callers.
    - `page` integer, required: The page this response is, 1-based.
    - `per_page` integer, required: Page size. Same value as `limit`.
    - `limit` integer, required: Page size. Alias of `per_page`.
    - `total` integer: Total records matching the query across every page.
    - `totalPages` integer: How many pages the result set spans at the current `per_page`.

## Other responses

- `304`: Your copy is current. No body is sent, and this response does not count toward the daily request allowance.
- `400`: Validation error
- `401`: Missing or invalid API key
- `403`: The credential is valid and the caller is not permitted. Three causes, none of which reissuing a key changes: the plan is below the endpoint's tier, the account is suspended, or the key is not attached to the thing being acted on, meaning a user account for `/v1/me` or a shop for `/v1/vendor`. Distinct from 401, which means the credential is missing, malformed or expired and a new one can work.
- `429`: A limit was reached. `RATE_LIMITED` is the per-minute limit: wait `Retry-After` seconds (a minute) and retry. `DAILY_CAP_EXCEEDED` is the plan's daily limit, per key: nothing will be served until the counters return to zero at midnight UTC. `MONTHLY_CAP_EXCEEDED` is the plan's monthly allowance, for the whole account: nothing will be served until midnight UTC on the first of next month, or until the plan changes. For both, `Retry-After` is the seconds until then and `error.resetsAt` says when as an instant. Calls made after a refusal are refused too and do not spend the month, and a free key that keeps calling is paused, so stop at the first one and resume at the reset.
- `500`: Internal server error

---

[API](https://skmtc.dev/gunspec/apis/gunspec-io-api.md) · [All operations](https://skmtc.dev/gunspec/apis/gunspec-io-api/llms.txt) · [OpenAPI document](https://skmtc.dev/gunspec/apis/gunspec-io-api/revisions/f2e974d8b05c?raw)
