# Wrapped Source

URL: /define/sources · Id: `term:wrapped-source`

> An outside source an API Product wraps, declared as one descriptor: its operations, Offer, meters, limits, tenancy and error map.

A Wrapped Source is an outside source an API [Product](/define/product) wraps, declared as one descriptor: its operations, Offer, meters, limits, tenancy and error map.

## Parts
| Field | Type | Required | What it is |
| --- | --- | --- | --- |
| `slug` | `string` | Yes | The source id, unique among sources. |
| `title` | `string` | No | The display name of the source. |
| `description` | `string` | No | What the source holds, in one line. |
| `origin` | `string` | No | The base URL every request goes to. |
| `transport` | `Transport` | No | How requests reach the upstream. |
| `auth` | `Auth` | No | How the source authenticates to the upstream. |
| `resources` | `Record<string, Resource>` | No | The operations of the upstream, by resource, each a list or a detail lookup. |
| `cache` | `CachePolicy` | No | The cache policy of every operation. |
| `retry` | `Retry` | No | The retry policy of every operation. |
| `transform` | `TransformStep[]` | No | The steps that shape each record, as data: `select`, `coerce`, `derive`, `validate` or `module`. |
| `composition` | `Composition` | No | How several steps combine: chain, parallel, race, hedge, merge or fallback. |
| `schedule` | `Schedule` | No | The jobs the source runs on a clock. |
| `offer` | `Offer` | No | The pricing document of the source: free or metered, checked fail-closed. |
| `scopes` | `Scope[]` | No | The scopes a caller can hold, each named. |
| `meters` | `Meter[]` | No | What the source counts: each meter with its name and unit. |
| `rateLimit` | `RateLimit` | No | A window and the most calls it allows. |
| `spendCeiling` | `SpendCeiling` | No | A ceiling on total spend, separate from the rate limit. |
| `tenancy` | `Tenancy` | No | Who owns the listing, whether it is house or third-party, and its mint. |
| `errorVocabulary` | `Record<string, Outcome>` | No | Maps each upstream error onto `OK`, `EMPTY`, `BLOCKED`, `NOT_FOUND` or `UPSTREAM`. |
| `discovery` | `Discovery` | No | The home of the source, its llms.txt and its examples. |
| `generatedBy` | `GeneratedBy` | No | On a descriptor a family expands: the family, catalog row, snapshot date and license. |

## Checks
- A descriptor names its source by a slug.
- A descriptor holds only the members its grammar defines, and any other member is refused.
- A house listing carries a mint, and a third-party upstream never does.
- An Offer declares its model, free or metered; free is never silent.
- A metered Offer declares a hard ceiling above 0.
- A metered Offer names the channel that answers a call over its ceiling.
- A metered Offer names where it is paid for.
- No field links the rate limit to the spend ceiling, so paying never lifts a rate limit.

## Example
```yaml title="tidecharts.example: the descriptor"
slug: tidecharts
title: Tidecharts
description: Tide predictions for coastal stations, wrapped from one public upstream.
origin: https://tides.example/api
resources:
  stations:
    list:
      path: /stations
      method: GET
    detail:
      path: /stations/{id}/predictions
      method: GET
      idQuery: id
offer:
  model: metered
  hardCeiling: 50
  overCeiling:
    channel: email
  monetization:
    surface: pricing
meters:
  - name: predictions
    unit: per-request
rateLimit:
  window: 1m
  max: 600
spendCeiling:
  ceiling: 50
tenancy:
  owner: tidecharts.example
  visibility: house
  mint:
    brand: Tidecharts
errorVocabulary:
  "404": NOT_FOUND
  "429": BLOCKED
  "503": UPSTREAM
discovery:
  home: https://tidecharts.example
  llmsTxt: /llms.txt
```