---
title: "Read back your listings"
method: GET
path: "/v1/vendor/offers"
tags: ["Seller"]
---

# Read back your listings

`GET /v1/vendor/offers`

## Request

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

What this shop currently holds, so a sync can diff before it writes and send the twelve rows that changed rather than all four hundred. Each row carries the catalogue record it points at, your price and currency, the link, publication status, which side last wrote it (`api` or `console`), when it was last refreshed, its `clickId`, and the clicks it earned over the last 30 days. `stockQty` appears here and in no public response: it is private from readers, not from the shop that entered it.

**Requires Enterprise tier or higher.**

## Query parameters

- `vendor` string
- `kind` 'attachment' | 'firearm'
- `status` 'draft' | 'published'
- `q` string
- `page` integer
- `per_page` integer

## Response `200`

Read back your listings

- object
  - `success` boolean, required: Always true on a successful response. Every error carries `false` and an `error` object instead.
  - `data` object[], required: One page of results. Use `pagination` to walk the rest.
    - `sku` string: The shop's own catalogue key for the listing. A seller's identifier, not ours: it is what `PATCH /v1/vendor/offers/{sku}` addresses.
    - `targetKind` 'attachment' | 'firearm': What a seller listing is for.
    - `targetId` string: Slug of the catalogued record the listing points at, in whichever catalog `targetKind` names.
    - `priceCents` integer: Price in integer minor units of `currency`, so cents for AUD. Never a float. Format with `Intl.NumberFormat` at render rather than dividing first.
    - `currency` string: ISO 4217 code the price is in, e.g. `AUD`. Prices are integer minor units; format with `Intl.NumberFormat` at render rather than dividing first.
    - `url` string: Absolute, directly fetchable URL.
    - `inStock` boolean: Whether the shop reports it in stock. Derived from `stockQty` where the shop tracks a count.
    - `stockQty` integer, nullable: Units you hold: 0 is out of stock, null is not tracked. Private to the shop, and never returned by a public offers endpoint.
    - `status` 'draft' | 'published': Whether a seller listing is public.
    - `source` string: Where the record came from: a curated entry, an inference, or an import.
    - `clicks` integer: Outbound clicks this listing earned over the last 30 days.
    - `updatedAt` string: When a field we serve last changed.
  - `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

- `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)
