# Baskets

> Reference basket reads, immutable versions, changes, methodology history, and paid-tier webhooks.

## GET /v1/baskets

List published reference baskets.

### Example

```bash
curl https://api.philidor.io/v1/baskets
```

### Response

```json
{
  "data": [
    {
      "id": "rwa-tbill-conservative",
      "name": "RWA T-Bill Conservative",
      "constituent_type": "asset",
      "version_id": "42",
      "effective_from": "2026-07-01T00:00:00Z",
      "content_hash": "abc123",
      "last_rebalanced_at": "2026-07-01T00:00:00Z"
    }
  ]
}
```

---

## GET /v1/baskets/\{id\}

Get the current basket version. Pass `at` to resolve the version effective at a historical timestamp.

### Query Parameters

| Parameter | Type   | Default | Description                              |
| --------- | ------ | ------- | ---------------------------------------- |
| at        | string | -       | ISO-8601 timestamp for historical lookup |

### Example

```bash
curl "https://api.philidor.io/v1/baskets/rwa-tbill-conservative"
```

### Response

```json
{
  "data": {
    "id": "rwa-tbill-conservative",
    "name": "RWA T-Bill Conservative",
    "version_id": "42",
    "effective_from": "2026-07-01T00:00:00Z",
    "constituent_type": "asset",
    "content_hash": "abc123",
    "methodology": {
      "summary": "Basket summary",
      "eligibility_rule": "Reviewed Prime and Core RWA assets",
      "weighting_rule": "Score-weighted",
      "refresh_rule": "Calendar and rating moves",
      "caps": {
        "single_name_pct": 25,
        "issuer_pct": 40,
        "floor_pct": 2
      },
      "version": "1.1.1",
      "doc_url": "https://docs.philidor.io/docs/methodology/baskets/rwa-tbill-conservative"
    },
    "constituents": [],
    "analytics": null,
    "support_status": "current",
    "retired_at": null
  }
}
```

Current-version responses include `ETag`, `s-maxage=60`, and `stale-while-revalidate`. `If-None-Match` returns `304` when the content hash matches.

---

## GET /v1/baskets/\{id\}/versions

List version history.

### Query Parameters

| Parameter | Type   | Default | Description               |
| --------- | ------ | ------- | ------------------------- |
| page      | number | 1       | Page number               |
| pageSize  | number | 50      | Results per page, max 200 |

### Example

```bash
curl "https://api.philidor.io/v1/baskets/rwa-tbill-conservative/versions"
```

### Response

```json
{
  "data": [
    {
      "version_id": "42",
      "basket_id": "rwa-tbill-conservative",
      "effective_from": "2026-07-01T00:00:00Z",
      "trigger_reason": "calendar_quarter",
      "prior_version_id": "41",
      "methodology_version": "1.1.1",
      "content_hash": "abc123",
      "signing_key_id": "basket-key-1",
      "created_at": "2026-07-01T00:00:00Z"
    }
  ],
  "meta": {
    "page": 1,
    "limit": 50,
    "total": 1,
    "totalPages": 1
  }
}
```

---

## GET /v1/baskets/\{id\}/version/\{versionId\}

Get an immutable basket version. Immutable responses use one-year cache headers. Retired versions return `410` with a successor pointer.

### Example

```bash
curl https://api.philidor.io/v1/baskets/rwa-tbill-conservative/version/42
```

### Response

Same shape as `GET /v1/baskets/{id}`.

---

## GET /v1/baskets/\{id\}/changes

Get constituent-level diffs for recent versions.

### Query Parameters

| Parameter | Type   | Default | Description                  |
| --------- | ------ | ------- | ---------------------------- |
| limit     | number | 20      | Versions to inspect, max 100 |

### Example

```bash
curl "https://api.philidor.io/v1/baskets/rwa-tbill-conservative/changes?limit=5"
```

### Response

```json
{
  "data": [
    {
      "version_id": "42",
      "prior_version_id": "41",
      "effective_from": "2026-07-01T00:00:00Z",
      "trigger_reason": "calendar_quarter",
      "added": [],
      "removed": [],
      "weight_changed": []
    }
  ]
}
```

---

## GET /v1/baskets/\{id\}/methodology/versions

List methodology versions used by a basket.

### Example

```bash
curl https://api.philidor.io/v1/baskets/rwa-tbill-conservative/methodology/versions
```

### Response

```json
{
  "data": [
    {
      "version": "1.1.1",
      "doc_url": "https://docs.philidor.io/docs/methodology/baskets/rwa-tbill-conservative",
      "content_hash": "abc123",
      "activated_at": "2026-07-01T00:00:00Z",
      "retired_at": null,
      "is_active": true
    }
  ]
}
```

## Webhooks

Webhook CRUD requires a growth or enterprise key.

| Method | Endpoint                                  |
| ------ | ----------------------------------------- |
| POST   | `/v1/baskets/{id}/webhooks`               |
| DELETE | `/v1/baskets/{id}/webhooks/{whId}`        |
| POST   | `/v1/baskets/{id}/webhooks/{whId}/replay` |

### Create Example

```bash
curl -X POST https://api.philidor.io/v1/baskets/rwa-tbill-conservative/webhooks \
  -H "Authorization: Bearer pk_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com/philidor-webhooks"}'
```

### Create Response

```json
{
  "data": {
    "id": 7,
    "basket_id": "rwa-tbill-conservative",
    "url": "https://example.com/philidor-webhooks",
    "secret": "whsec_...",
    "status": "active",
    "created_at": "2026-07-01T00:00:00Z"
  }
}
```

The secret is returned once.

### Signature Verification

Philidor signs the exact string `timestamp.body` with HMAC-SHA-256 and sends the result in `X-Philidor-Signature`.

```text
t=<unix_ts>,v1=<hex>
```

```typescript

function verifyPhilidorWebhook(secret: string, body: string, header: string) {
  const parts = Object.fromEntries(header.split(',').map((part) => part.split('=')));
  const timestamp = Number(parts.t);
  const expected = createHmac('sha256', secret).update(`${timestamp}.${body}`).digest('hex');
  return timingSafeEqual(Buffer.from(expected, 'hex'), Buffer.from(parts.v1, 'hex'));
}
```