# POST /v1/archive/buff

Native BUFF sale price samples and daily total supply from September 6, 2024.

Returns BUFF sale prices and daily total supply from BUFF's sale trends chart.

- Sale prices from September 6, 2024
- Daily `total_supply` from September 6, 2024 (for items where BUFF reports it)

Data updates ~1x per day. Max 100 items per request.

## Access

Requires a Scale or Enterprise API key.

## Sample density

BUFF samples recent history more densely/frequently than older history. A sample only exists where a sale occurred, so illiquid items have larger gaps at each interval.

| From | Typical spacing |
| --- | --- |
| September 2026 | 1-3 hours |
| August 2026 | ~12 hours |
| March 2026 | ~2 days |
| September 2025 | ~4 days |
| September 2024 | ~6 days |

## Request

`POST https://api.cs2.sh/v1/archive/buff`

**curl**

```bash
curl -X POST https://api.cs2.sh/v1/archive/buff \
  -H "Authorization: Bearer <<YOUR_API_KEY>>" \
  -H "Accept-Encoding: gzip" --compressed \
  -H "Content-Type: application/json" \
  -d '{
  "items": [
    "★ Karambit | Doppler (Factory New)"
  ],
  "start": "2024-09-01",
  "end": "2026-09-07"
}'
```

**Python**

```python
import requests

headers = {
    "Authorization": "Bearer <<YOUR_API_KEY>>",
    "Accept-Encoding": "gzip",
    "Content-Type": "application/json",
}

payload = {
    "items": ["★ Karambit | Doppler (Factory New)"],
    "start": "2024-09-01",
    "end": "2026-09-07",
}

response = requests.post(
    "https://api.cs2.sh/v1/archive/buff",
    headers=headers,
    json=payload,
)

response.raise_for_status()
data = response.json()
```

**Node**

```javascript
const headers = {
  "Authorization": "Bearer <<YOUR_API_KEY>>",
  "Accept-Encoding": "gzip",
  "Content-Type": "application/json",
};

const response = await fetch("https://api.cs2.sh/v1/archive/buff", {
  method: "POST",
  headers,
  body: JSON.stringify({
    "items": [
      "★ Karambit | Doppler (Factory New)"
    ],
    "start": "2024-09-01",
    "end": "2026-09-07"
  }),
});

if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();
```

**Go**

```go
package main

import (
    "bytes"
    "compress/gzip"
    "encoding/json"
    "fmt"
    "io"
    "net/http"
)

func main() {
    payload := map[string]any{
        "items": []any{
            "★ Karambit | Doppler (Factory New)",
        },
        "start": "2024-09-01",
        "end": "2026-09-07",
    }
    body, _ := json.Marshal(payload)
    req, _ := http.NewRequest("POST", "https://api.cs2.sh/v1/archive/buff", bytes.NewReader(body))
    req.Header.Set("Content-Type", "application/json")
    req.Header.Set("Authorization", "Bearer <<YOUR_API_KEY>>")
    req.Header.Set("Accept-Encoding", "gzip")

    resp, err := http.DefaultClient.Do(req)
    if err != nil { panic(err) }
    defer resp.Body.Close()

    if resp.StatusCode < 200 || resp.StatusCode >= 300 {
        body, _ := io.ReadAll(resp.Body)
        panic(fmt.Sprintf("HTTP %d: %s", resp.StatusCode, body))
    }

    var reader io.Reader = resp.Body
    if resp.Header.Get("Content-Encoding") == "gzip" {
        gz, err := gzip.NewReader(resp.Body)
        if err != nil { panic(err) }
        defer gz.Close()
        reader = gz
    }

    var data any
    if err := json.NewDecoder(reader).Decode(&data); err != nil { panic(err) }
    fmt.Printf("%#v\n", data)
}
```

**R**

```r
library(httr2)

payload <- list(
  items = list(
    "★ Karambit | Doppler (Factory New)"
  ),
  start = "2024-09-01",
  end = "2026-09-07"
)

resp <- request("https://api.cs2.sh/v1/archive/buff") |>
  req_headers(
    Authorization = "Bearer <<YOUR_API_KEY>>",
    `Accept-Encoding` = "gzip"
  ) |>
  req_body_json(payload) |>
  req_perform()

data <- resp_body_json(resp)
```

## Parameters

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `items` | `string[]` | Yes | List of `market_hash_name` values (max 100). |
| `start` | `string` | No | Start date/time as YYYY-MM-DD or RFC3339, inclusive. Defaults to the start of collected history. |
| `end` | `string` | No | End date/time as YYYY-MM-DD or RFC3339, exclusive. Defaults to now. |

## Response

```json
{
  "response_time": "2026-09-07T03:06:32.382569714Z",
  "currency": "USD",
  "start": "2026-09-03T00:00:00Z",
  "end": "2026-09-06T00:00:00Z",
  "items": {
    "★ Karambit | Doppler (Factory New)": {
      "market_hash_name": "★ Karambit | Doppler (Factory New)",
      "count": 23,
      "data": [
        {
          "time": "2026-09-03T00:00:00Z",
          "sale_price": 1872.55,
          "total_supply": 30164
        },
        {
          "time": "2026-09-03T03:00:00Z",
          "sale_price": 1469.43,
          "total_supply": 30164
        }
      ],
      "variants": {
        "Phase 2": {
          "market_hash_name": "★ Karambit | Doppler (Factory New)",
          "name": "★ Karambit | Doppler (Factory New) | Phase 2",
          "display_name": "Phase 2",
          "version": "p2",
          "count": 28,
          "data": [
            {
              "time": "2026-09-03T00:00:00Z",
              "sale_price": 1872.55,
              "total_supply": 7509
            }
          ]
        }
      }
    }
  }
}
```

## Response fields

[ArchiveBuffResponse](/docs/objects#archivebuffresponse) fields:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `response_time` | `string (date-time)` | Yes | When the response was generated. |
| `currency` | `string` | Yes | Currency code (always `USD`). |
| `start` | `string (date-time)` | Yes | Effective start of the queried range, exactly as requested or defaulted. Inclusive. |
| `end` | `string (date-time)` | Yes | Effective end of the queried range, exactly as requested or defaulted. Exclusive. |
| `items` | [`Record<string, ArchiveBuffItem>`](/docs/objects#archivebuffitem) | Yes | Map of `market_hash_name` to BUFF sale series. |
| `errors` | [ItemError[]](/docs/objects#itemerror) | No | Per-item failures alongside successful results (partial success). |

## Samples

| Field | Description |
| --- | --- |
| `items.<name>.count` | Number of samples. |
| `items.<name>.data[]` | Native BUFF chart samples. |
| `data[].time` | Sample time. |
| `data[].sale_price` | Sale price, USD, converted at the sale date's exchange rate. |
| `data[].total_supply` | BUFF-reported total supply for the sample's day (UTC+8). |
| `items.<name>.variants` | The same shape per variant. |

- `time` is present on every sample.
- `sale_price` can be `null` when the sale date's exchange rate is not stored yet, or on a supply-only day.
- `total_supply` can be `null` when BUFF reported no supply for that day.
- A day with supply and no sales returns one sample at China midnight (16:00 UTC).
- `count` is the number of samples. It is not sale volume.
- Variants appear under `variants` when BUFF sale history exists for that variant.
- Valid requested items with no BUFF sale history return `not_in_archive`.

Full schemas: [ArchiveBuffItem](/docs/objects#archivebuffitem), [ArchiveBuffVariant](/docs/objects#archivebuffvariant), [ArchiveBuffPoint](/docs/objects#archivebuffpoint).

### ArchiveBuffItem

BUFF sale samples and daily supply for a single item, as one chronological series.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `market_hash_name` | `string` | Yes | The base item's `market_hash_name`. |
| `count` | `integer` | Yes | Number of points in `data`. |
| `data` | [ArchiveBuffPoint[]](/docs/objects#archivebuffpoint) | Yes | Sale samples and supply-only rows in chronological order, one point per timestamp. |
| `variants` | [`Record<string, ArchiveBuffVariant>`](/docs/objects#archivebuffvariant) | No | Per-variant BUFF series for items with Doppler and Gamma Doppler phases or Case Hardened tiers. Keyed by display name and omitted when empty. A variant series never falls back to base history. |

### ArchiveBuffVariant

BUFF sale samples and daily supply for one Doppler or Gamma Doppler phase or Case Hardened tier.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `market_hash_name` | `string` | Yes | The base item's `market_hash_name`. The full variant name is `name`. |
| `name` | `string` | Yes | The variant's full `market_hash_name`, e.g. `★ Karambit \| Doppler (Factory New) \| Phase 2`. |
| `display_name` | `string` | Yes | Human-readable variant label (e.g. `Phase 1`, `Ruby`, `Tier 1`, `Blue Gem`). |
| `version` | `string` | Yes | Stable variant code. Switch on this in client code. |
| `count` | `integer` | Yes | Number of points in `data`. |
| `data` | [ArchiveBuffPoint[]](/docs/objects#archivebuffpoint) | Yes | Sale samples and supply-only rows in chronological order, one point per timestamp. |

### ArchiveBuffPoint

One sample from BUFF's sale price chart, or a supply-only row on a day with no sampled sale. A sample is a chart point, not a verified individual trade, and BUFF reports no sale volume.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `time` | `string (date-time)` | Yes | Sample time from BUFF's chart, UTC. Supply-only rows are stamped at China midnight (16:00 UTC). |
| `sale_price` | `number \| null` | Yes | Sale price (USD), converted from CNY at the sale date's historical rate. `null` on supply-only rows and on sales whose date has no stored rate yet. |
| `total_supply` | `integer \| null` | Yes | Total supply BUFF reported for the sample's China-calendar day (UTC+8). `null` when no supply was reported that day. |

## Errors

`404 not_found` means none of the requested valid items have BUFF sale history in the window. Partial results return `200` with `errors[]`; possible item codes are `unknown_item`, `invalid_format`, and `not_in_archive`. See [Partial success](/docs/using-the-api#partial-success) and [Request errors](/docs/using-the-api#request-errors).
